3#include <Tempest/Application>
4#include <Tempest/SoundEffect>
5#include <Tempest/Sound>
14using namespace Tempest;
21 const size_t reserve=2048;
22 pcm.reserve(reserve*2);
23 pcmMix.reserve(reserve*2);
38 embellishment.store(e);
43 current->volume.store(v);
50int64_t Mixer::nextNoteOn(PatternList::PatternInternal& part,int64_t b,int64_t e) {
51 int64_t nextDt = std::numeric_limits<int64_t>::max();
52 int64_t timeTotal =
toSamples(part.timeTotal);
58 for(
auto& i:part.waves) {
60 if((b<at && at<=e)^inv) {
64 if(t<nextDt && i.duration>0)
72int64_t Mixer::nextNoteOff(int64_t b, int64_t ) {
73 int64_t actT = std::numeric_limits<int64_t>::max();
77 int64_t dt = at>b ? at-b : 0;
84void Mixer::noteOn(std::shared_ptr<PatternInternal>& pattern, PatternList::Note *r) {
85 if(!checkVariation(*r))
89 a.at = sampleCursor +
toSamples(r->duration);
90 a.ticket = r->inst->font.noteOn(r->note,r->velosity);
94 for(
auto& i:uniqInstr)
104 uniqInstr.push_back(u);
106 a.parent = &uniqInstr.back();
112void Mixer::noteOn(std::shared_ptr<PatternInternal>& pattern, int64_t time) {
116 for(
auto& i:pattern->waves) {
124 throw std::runtime_error(
"mixer critical error");
127void Mixer::noteOff(int64_t time) {
129 for(
size_t i=0;i<active.size();++i){
130 if(active[i].at>time) {
131 active[sz]=active[i];
135 active[i].parent->counter--;
141void Mixer::nextPattern() {
143 if(mus->pptn.size()==0) {
150 for(
size_t i=0;i<mus->pptn.size();++i) {
151 if(mus->pptn[i]->timeTotal==0)
153 pattern = std::shared_ptr<PatternInternal>(mus,mus->pptn[i].get());
157 for(
size_t i=0;i<mus->pptn.size();++i){
158 if(mus->pptn[i].get()==prev.get()) {
159 nextOff = (i+1)%mus->pptn.size();
165 const int groove = getGroove();
166 if(nextMus!=
nullptr) {
169 grooveCounter.store(0);
174 for(
size_t i=0;i<mus->pptn.size();++i) {
175 auto& ptr = mus->pptn[(i+nextOff)%mus->pptn.size()];
176 if(ptr->timeTotal==0)
178 if(ptr->ptnh.wEmbellishment!=em)
181 if(mus->groove.size()==0 || (ptr->ptnh.bGrooveBottom<=groove && groove<=ptr->ptnh.bGrooveTop)) {
182 pattern = std::shared_ptr<PatternList::PatternInternal>(mus,ptr.get());
187 if(pattern->timeTotal>0) {
188 grooveCounter.fetch_add(1);
192 while(active.size()>0)
193 noteOff(active[0].at);
196 patStart = sampleCursor;
197 patEnd = patStart+
toSamples(pattern->timeTotal);
198 for(
auto& i:pattern->waves)
202 variationCounter.fetch_add(1);
205Mixer::Step Mixer::stepInc(PatternInternal& pptn, int64_t b, int64_t e, int64_t samplesRemain) {
206 int64_t nextT = nextNoteOn (pptn,b,e);
207 int64_t offT = nextNoteOff(b,e);
208 int64_t samples = std::min(offT,nextT);
211 if(samples>samplesRemain) {
212 s.samples=samplesRemain;
222void Mixer::stepApply(std::shared_ptr<PatternInternal> &pptn,
const Mixer::Step &s,int64_t b) {
223 if(s.nextOff<s.nextOn) {
224 noteOff(s.nextOff+b);
226 if(s.nextOff>s.nextOn) {
227 noteOn (pptn,s.nextOn+b);
229 if(s.nextOff==s.nextOn) {
230 noteOff(s.nextOff+b);
231 noteOn (pptn,s.nextOn+b);
235std::shared_ptr<Mixer::PatternInternal> Mixer::checkPattern(std::shared_ptr<PatternInternal> p) {
241 grooveCounter.store(0);
243 for(
auto& i:cur->pptn)
244 if(i.get()==p.get()) {
254 std::memset(out,0,2*samples*
sizeof(int16_t));
262 const int64_t samplesTotal =
toSamples(cur->timeTotal);
263 if(samplesTotal==0) {
268 auto pat = checkPattern(pattern);
270 size_t samplesRemain = samples;
271 while(samplesRemain>0) {
274 const int64_t remain = std::min(patEnd-sampleCursor,int64_t(samplesRemain));
275 const int64_t b = (sampleCursor );
276 const int64_t e = (sampleCursor+remain);
279 const float volume = cur->volume.load()*this->volume.load();
281 const Step stp = stepInc(pptn,b,e,remain);
282 implMix(pptn,volume,out,
size_t(stp.samples));
284 if(remain!=stp.samples)
285 stepApply(pat,stp,sampleCursor);
287 sampleCursor += stp.samples;
288 out += stp.samples*2;
289 samplesRemain-= size_t(stp.samples);
292 if(stp.nextOn==std::numeric_limits<int64_t>::max() && uniqInstr.size()==0)
293 sampleCursor = patEnd;
295 if(sampleCursor==patEnd || nextMus!=
nullptr) {
302 uniqInstr.remove_if([](Instr& i){
303 return i.counter==0 && !i.ptr->font.hasNotes();
311void Mixer::implMix(PatternInternal &pptn,
float volume, int16_t *out,
size_t cnt) {
312 const size_t cnt2=cnt*2;
317 std::memset(pcmMix.data(),0,cnt2*
sizeof(pcmMix[0]));
319 for(
auto& i:uniqInstr) {
321 if(!ins.font.hasNotes())
324 std::memset(pcm.data(),0,cnt2*
sizeof(pcm[0]));
325 ins.font.mix(pcm.data(),cnt);
327 float insVolume = std::pow(ins.volume,2.f);
328 if(ins.key==5 || ins.key==6) {
332 const bool hasVol = hasVolumeCurves(pptn,i);
334 volFromCurve(pptn,i,vol);
335 for(
size_t r=0;r<cnt2;++r) {
337 pcmMix[r] += pcm[r]*insVolume*(v*v);
340 for(
size_t r=0;r<cnt2;++r) {
342 pcmMix[r] += pcm[r]*insVolume*(v*v);
347 for(
size_t i=0;i<cnt2;++i) {
348 float v = pcmMix[i]*volume;
349 out[i] = (v < -1.00004566f ? int16_t(-32768) : (v > 1.00001514f ? int16_t(32767) : int16_t(v * 32767.5f)));
353void Mixer::volFromCurve(PatternInternal &part,Instr& inst,std::vector<float> &v) {
354 float& base = inst.volLast;
358 const int64_t shift = sampleCursor-patStart;
361 for(
auto& i:part.volume) {
364 if(!checkVariation(i))
368 int64_t e =
toSamples(i.at+i.duration)-shift;
369 if((s>=0 &&
size_t(s)>v.size()) || e<0)
372 const size_t begin = size_t(std::max<int64_t>(s,0));
373 const size_t size = std::min(
size_t(e),v.size());
374 const float range = float(e-s);
375 const float diffV = i.endV-i.startV;
376 const float shift = i.startV;
377 const float endV = i.endV;
381 for(
size_t i=begin;i<size;++i) {
382 float val = (float(i)-float(s))/range;
383 v[i] = val*diffV+shift;
388 for(
size_t i=begin;i<size;++i) {
394 for(
size_t i=begin;i<size;++i) {
395 float val = (float(i)-float(s))/range;
396 v[i] = std::pow(val,2.f)*diffV+shift;
401 for(
size_t i=begin;i<size;++i) {
402 float val = (float(i)-float(s))/range;
403 v[i] = std::sqrt(val)*diffV+shift;
408 for(
size_t i=begin;i<size;++i) {
409 float linear = (float(i)-float(s))/range;
410 float val = std::sin(
float(M_PI)*linear*0.5f);
411 v[i] = val*diffV+shift;
421int Mixer::getGroove()
const {
424 if(mus.groove.size()==0)
426 auto& g = mus.groove[grooveCounter.load()%mus.groove.size()];
427 return g.bGrooveLevel;
430bool Mixer::hasVolumeCurves(Mixer::PatternInternal& part, Mixer::Instr& inst)
const {
431 for(
auto& i:part.volume) {
434 if(!checkVariation(i))
442bool Mixer::checkVariation(
const T& item)
const {
443 if(item.inst->dwVarCount==0)
445 uint32_t vbit = variationCounter.load()%item.inst->dwVarCount;
446 if((item.dwVariation & (1<<vbit))==0)
void setMusic(const Music &m, DMUS_EMBELLISHT_TYPES embellishment=DMUS_EMBELLISHT_NORMAL)
void setMusicVolume(float v)
int64_t currentPlayTime() const
void mix(int16_t *out, size_t samples)
static void noteOff(Ticket &t)
static int64_t toSamples(uint64_t time)