void MusicEffect::Render(RenderBuffer &buffer, int bars, const std::string& type, int sensitivity, bool scale, const std::string& scalenotes, int offsetx, int startnote, int endnote, const std::string& colourtreatment, bool fade) { // no point if we have no media if (buffer.GetMedia() == NULL) { return; } int nType = DecodeType(type); int nTreatment = DecodeColourTreatment(colourtreatment); int nScaleNotes = DecodeScaleNotes(scalenotes); // Grab our cache MusicRenderCache *cache = (MusicRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new MusicRenderCache(); buffer.infoCache[id] = cache; } int &_bars = cache->_bars; int &_startNote = cache->_startNote; int &_endNote = cache->_endNote; int &_type = cache->_type; int &_offsetx = cache->_offsetx; bool &_scale = cache->_scale; int &_sensitivity = cache->_sensitivity; int &_scalenotes = cache->_scalenotes; bool &_fade = cache->_fade; int& _colourTreatment = cache->_colourTreatment; std::vector<std::list<MusicEvent*>*>& _events = cache->_events; int actualbars = std::min(bars, std::min(endnote - startnote + 1, buffer.BufferWi - offsetx)); int notesperbar = (endnote - startnote + 1) / actualbars; int actualendnote = startnote + std::min(endnote, actualbars * notesperbar); int lightsperbar = 0.5 + (float)(buffer.BufferWi - offsetx) / (float)actualbars; // Check for config changes which require us to reset if (buffer.needToInit || _bars != bars || _type != nType || _startNote != startnote || _endNote != endnote || _offsetx != offsetx || _scale != scale || _scalenotes != nScaleNotes || _sensitivity != sensitivity || _colourTreatment != nTreatment || _fade != fade) { buffer.needToInit = false; _bars = bars; _fade = fade; _startNote = startnote; _endNote = endnote; _colourTreatment = nTreatment; _type = nType; _offsetx = offsetx; _scale = scale; _sensitivity = sensitivity; _scalenotes = nScaleNotes; cache->ClearEvents(); // We limit bars to the width of the model less the x offset CreateEvents(buffer, _events, _startNote, actualendnote, actualbars, _scalenotes, _sensitivity); } int per = 1; if (_scale) { per = lightsperbar; } try { for (int x = 0; x < _events.size(); x++) { for (int i = 0; i < per; i++) { switch (_type) { case 1: RenderMorph(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, *_events[x], _colourTreatment, false, fade); break; case 2: RenderMorph(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, *_events[x], _colourTreatment, true, fade); break; case 3: RenderCollide(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, true /* collide */, *_events[x], _colourTreatment, fade); break; case 4: RenderCollide(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, false /* uncollide */,* _events[x], _colourTreatment, fade); break; case 5: RenderOn(buffer, (x*per) + i + _offsetx, _bars, _startNote, _endNote, *_events[x], _colourTreatment, fade); break; } } } } catch (...) { // This is here to let me catch any exceptions and stop the exception causing the render thread to die //int a = 0; } }
void MusicEffect::CreateEvents(RenderBuffer& buffer, std::vector<std::list<MusicEvent*>*>& events, int startNote, int endNote, int bars, int scalenotes, int sensitivity) { // must have media if (buffer.GetMedia() == NULL) { return; } float notesperbar = ((float)endNote - (float)startNote + 1.0) / (float)bars; // use notes per bar // use multiple notes of data per output string using the maximum of these notes intensities std::map<int /*bar*/, std::map<int /*frame*/, float>> data; std::map<int /*bar*/, float> max; float overallmax = 0.0; for (int b = 0; b < bars; b++) { max[b] = 0.0; } // go through each frame and extract the data i need for (int f = buffer.curEffStartPer; f <= buffer.curEffEndPer; f++) { std::list<float>* pdata = buffer.GetMedia()->GetFrameData(f, FRAMEDATATYPE::FRAMEDATA_VU, ""); auto pn = pdata->begin(); // skip to start note for (int i = 0; i < startNote; i++) { ++pn; } for (int b = 0; b < bars && pn != pdata->end(); b++) { float val = 0.0; for (int n = 0; n < (int)notesperbar; n++) { val = std::max(val, *pn); ++pn; } data[b][f] = val; max[b] = std::max(max[b], val); overallmax = std::max(overallmax, val); } } for (int b = 0; b < bars; b++) { events.push_back(new std::list<MusicEvent*>()); float notesensitivity; if (scalenotes == 1) { notesensitivity = (float)sensitivity / 100.0; } else if (scalenotes == 2) { notesensitivity = (float)sensitivity / 100.0 * max[b]; } else { notesensitivity = (float)sensitivity / 100.0 * overallmax; } int startframe = -1; // extract the value for this note int frame = buffer.curEffStartPer; for (auto f = data[b].begin(); f != data[b].end(); ++f) { if (f->second > notesensitivity) { startframe = frame; while (f != data[b].end() && f->second > notesensitivity) { ++f; frame++; } --f; frame--; if (frame - startframe >= MINIMUMEVENTLENGTH) { events[b]->push_back(new MusicEvent(startframe, frame - startframe)); } } frame++; } } }
void FireworksEffect::Render(Effect *effect, const SettingsMap &SettingsMap, RenderBuffer &buffer) { int Number_Explosions = SettingsMap.GetInt("SLIDER_Fireworks_Explosions", 16); int Count = SettingsMap.GetInt("SLIDER_Fireworks_Count", 50); float Velocity = SettingsMap.GetDouble("SLIDER_Fireworks_Velocity", 2.0f); int Fade = SettingsMap.GetInt("SLIDER_Fireworks_Fade", 50); float f = 0.0; bool useMusic = SettingsMap.GetBool("CHECKBOX_Fireworks_UseMusic", false); float sensitivity = (float)SettingsMap.GetInt("SLIDER_Fireworks_Sensitivity", 50) / 100.0; bool useTiming = SettingsMap.GetBool("CHECKBOX_FIRETIMING", false); wxString timing = SettingsMap.Get("CHOICE_FIRETIMINGTRACK", ""); if (timing == "") useTiming = false; if (useMusic) { if (buffer.GetMedia() != nullptr) { std::list<float>* pf = buffer.GetMedia()->GetFrameData(buffer.curPeriod, FRAMEDATA_HIGH, ""); if (pf != nullptr) { f = *pf->begin(); } } } FireworksRenderCache *cache = (FireworksRenderCache*)buffer.infoCache[id]; if (cache == nullptr) { cache = new FireworksRenderCache(); buffer.infoCache[id] = cache; } int& next = cache->next; int& sincelasttriggered = cache->sincelasttriggered; int x25,x75,y25,y75; //float velocity = 3.5; int ColorIdx; float v; HSVValue hsv; size_t colorcnt = buffer.GetColorCount(); if (buffer.needToInit) { SetPanelTimingTracks(); cache->sincelasttriggered = 0; cache->next = 0; buffer.needToInit = false; for(int i=0; i<maxFlakes; i++) { cache->fireworkBursts[i]._bActive = false; } for (int x = 0; x < Number_Explosions; x++) { double start = -1; if (!useMusic) { start = buffer.curEffStartPer + buffer.rand01() * (buffer.curEffEndPer - buffer.curEffStartPer); } x25=(int)buffer.BufferWi*0.25; x75=(int)buffer.BufferWi*0.75; y25=(int)buffer.BufferHt*0.25; y75=(int)buffer.BufferHt*0.75; int startX; int startY; if((x75-x25)>0) startX = x25 + rand()%(x75-x25); else startX=0; if((y75-y25)>0) startY = y25 + rand()%(y75-y25); else startY=0; // Create a new burst ColorIdx=rand() % colorcnt; // Select random numbers from 0 up to number of colors the user has checked. 0-5 if 6 boxes checked for(int i=0; i<Count; i++) { cache->fireworkBursts[x * Count + i].Reset(startX, startY, false, Velocity, ColorIdx, start); } } if (timing != "") { effect->GetParentEffectLayer()->GetParentElement()->GetSequenceElements()->AddRenderDependency(timing.ToStdString(), buffer.cur_model); } } if (useMusic) { // only trigger a firework if music is greater than the sensitivity if (f > sensitivity) { // trigger if it was not previously triggered or has been triggered for REPEATTRIGGER frames if (sincelasttriggered == 0 || sincelasttriggered > REPEATTRIGGER) { // activate all the particles in the next firework for (int j = 0; j < Count; j++) { cache->fireworkBursts[Count*next + j]._bActive = true; buffer.palette.GetHSV(cache->fireworkBursts[Count*next + j]._colorindex, hsv); // Now go and get the hsv value for this ColorIdx cache->fireworkBursts[Count*next + j]._hsv = hsv; } // use the next firework next time next++; if (next == Number_Explosions) { next = 0; } } // if music is over the trigger level for REPEATTRIGGER frames then we will trigger another firework sincelasttriggered++; if (sincelasttriggered > REPEATTRIGGER) { sincelasttriggered = 0; } } else { // not triggered so clear last triggered counter sincelasttriggered = 0; } } if (useTiming) { if (mSequenceElements == nullptr) { // no timing tracks ... this shouldnt happen } else { // Load the names of the timing tracks Element* t = nullptr; for (size_t l = 0; l < mSequenceElements->GetElementCount(); l++) { Element* e = mSequenceElements->GetElement(l); if (e->GetEffectLayerCount() == 1 && e->GetType() == ELEMENT_TYPE_TIMING) { if (e->GetName() == timing) { t = e; break; } } } if (t == nullptr) { // timing track not found ... this shouldnt happen } else { sincelasttriggered = 0; EffectLayer* el = t->GetEffectLayer(0); for (int j = 0; j < el->GetEffectCount(); j++) { if (buffer.curPeriod == el->GetEffect(j)->GetStartTimeMS() / buffer.frameTimeInMs || buffer.curPeriod == el->GetEffect(j)->GetEndTimeMS() / buffer.frameTimeInMs) { // activate all the particles in the next firework for (int k = 0; k < Count; k++) { cache->fireworkBursts[Count*next + k]._bActive = true; buffer.palette.GetHSV(cache->fireworkBursts[Count*next + k]._colorindex, hsv); // Now go and get the hsv value for this ColorIdx cache->fireworkBursts[Count*next + k]._hsv = hsv; } // use the next firework next time next++; if (next == Number_Explosions) { next = 0; } break; } } } } } for (int i=0; i<(Count*Number_Explosions); i++) { if (!useMusic && !useTiming) { if (cache->fireworkBursts[i].startPeriod == buffer.curPeriod) { cache->fireworkBursts[i]._bActive = true; buffer.palette.GetHSV(cache->fireworkBursts[i]._colorindex, hsv); // Now go and get the hsv value for this ColorIdx cache->fireworkBursts[i]._hsv = hsv; } } // ... active flakes: if (cache->fireworkBursts[i]._bActive) { // Update position cache->fireworkBursts[i]._x += cache->fireworkBursts[i]._dx; cache->fireworkBursts[i]._y += (-cache->fireworkBursts[i]._dy - cache->fireworkBursts[i]._cycles*cache->fireworkBursts[i]._cycles/10000000.0); // If this flake run for more than maxCycle or this flake is out of bounds, time to switch it off cache->fireworkBursts[i]._cycles+=20; if (cache->fireworkBursts[i]._cycles >= 10000 || cache->fireworkBursts[i]._y >= buffer.BufferHt || cache->fireworkBursts[i]._y < 0 || cache->fireworkBursts[i]._x < 0. || cache->fireworkBursts[i]._x >= buffer.BufferWi) { cache->fireworkBursts[i]._bActive = false; if (useMusic) { cache->fireworkBursts[i].Reset(); } continue; } } if(cache->fireworkBursts[i]._bActive == true) { v = ((Fade*10.0)-cache->fireworkBursts[i]._cycles)/(Fade*10.0); if (v<0) v=0.0; if (buffer.allowAlpha) { xlColor c(cache->fireworkBursts[i]._hsv); c.alpha = 255.0 * v; buffer.SetPixel(cache->fireworkBursts[i]._x, cache->fireworkBursts[i]._y, c); } else { hsv=cache->fireworkBursts[i]._hsv; hsv.value=v; buffer.SetPixel(cache->fireworkBursts[i]._x, cache->fireworkBursts[i]._y, hsv); } } } }