void SynthesizeChannel(ChannelState& dst, AYM::ChannelBuilder& channel, AYM::TrackBuilder& track) { const Ornament::Line& curOrnamentLine = *dst.OrnamentIterator.GetLine(); const int_t noteAddon = dst.NoteAccumulator.Update(curOrnamentLine.NoteAddon, curOrnamentLine.KeepNoteAddon); const int_t noiseAddon = dst.NoiseAccumulator.Update(curOrnamentLine.NoiseAddon, curOrnamentLine.KeepNoiseAddon); dst.OrnamentIterator.Next(); if (const Sample::Line* curSampleLine = dst.SampleIterator.GetLine()) { //apply noise const int_t sampleNoiseAddon = dst.SampleNoiseAccumulator.Update(curSampleLine->Noise, curSampleLine->AccumulateNoise); if (curSampleLine->NoiseMask) { channel.DisableNoise(); } else { track.SetNoise(dst.Noise + noiseAddon + sampleNoiseAddon); } //apply tone dst.ToneAddon = dst.ToneAccumulator.Update(curSampleLine->Tone, curSampleLine->AccumulateTone); if (curSampleLine->ToneMask) { channel.DisableTone(); } //apply level dst.VolumeSlide += curSampleLine->VolSlide; const int_t volume = Math::Clamp<int_t>(curSampleLine->Level + dst.VolumeSlide, 0, 15); const uint_t level = ((dst.Volume * 17 + (dst.Volume > 7)) * volume + 128) / 256; channel.SetLevel(level); const uint_t envelope = dst.EnvelopeAccumulator.Update(curSampleLine->EnvelopeAddon, curSampleLine->AccumulateEnvelope); if (curSampleLine->EnableEnvelope && dst.EnvelopeEnabled) { channel.EnableEnvelope(); track.SetEnvelopeTone(dst.Envelope - envelope); } dst.SampleIterator.Next(); } else { channel.SetLevel(0); channel.DisableTone(); channel.DisableNoise(); } channel.SetTone(dst.Note + noteAddon, dst.ToneAddon + dst.ToneSlide.Update()); }
void SynthesizeChannel(ChannelState& dst, AYM::ChannelBuilder& channel, AYM::TrackBuilder& track) { if (!dst.Enabled) { channel.SetLevel(0); return; } const Sample& curSample = Data->Samples.Get(dst.CurrentSampleNum); const Sample::Line& curSampleLine = curSample.GetLine(dst.PosInSample); const Ornament& curOrnament = Data->Ornaments.Get(dst.CurrentOrnamentNum); const Ornament::Line& curOrnamentLine = curOrnament.GetLine(dst.PosInOrnament); //calculate volume addon if (dst.VolSlideCounter >= 2) { dst.VolSlideCounter--; } else if (dst.VolSlideCounter) { dst.VolumeAddon += dst.VolSlideAddon; dst.VolSlideCounter = dst.VolSlideDelay; } dst.VolumeAddon += curSampleLine.VolSlide; dst.VolumeAddon = Math::Clamp<int_t>(dst.VolumeAddon, -15, 15); //calculate tone dst.ToneDeviation += curSampleLine.ToneDeviation; dst.NoteAddon += curOrnamentLine.NoteAddon; const int_t halfTone = int_t(dst.Note) + dst.NoteAddon; const int_t toneAddon = dst.ToneDeviation + dst.Sliding / 16; //apply tone channel.SetTone(halfTone, toneAddon); //apply level channel.SetLevel((dst.Volume + 1) * Math::Clamp<int_t>(dst.VolumeAddon + curSampleLine.Level, 0, 15) / 16); //apply envelope if (dst.Envelope && curSampleLine.EnableEnvelope) { channel.EnableEnvelope(); } //calculate noise dst.CurrentNoise += curOrnamentLine.NoiseAddon; //mixer if (curSampleLine.ToneMask) { channel.DisableTone(); } if (curSampleLine.NoiseMask && curSampleLine.EnableEnvelope) { EnvelopeTone += curSampleLine.Adding; track.SetEnvelopeTone(EnvelopeTone); } else { dst.CurrentNoise += curSampleLine.Adding; } if (!curSampleLine.NoiseMask) { track.SetNoise((dst.CurrentNoise + dst.Sliding / 256) & 0x1f); } else { channel.DisableNoise(); } //recalc positions if (dst.SlidingSteps != 0) { if (dst.SlidingSteps > 0) { if (!--dst.SlidingSteps && LIMITER != dst.SlidingTargetNote) //finish slide to note { dst.Note = dst.SlidingTargetNote; dst.SlidingTargetNote = LIMITER; dst.Sliding = dst.Glissade = 0; } } dst.Sliding += dst.Glissade; } if (dst.PosInSample++ >= curSample.GetLoopLimit()) { if (!dst.BreakSample) { dst.PosInSample = curSample.GetLoop(); } else if (dst.PosInSample >= curSample.GetSize()) { dst.Enabled = false; } } if (dst.PosInOrnament++ >= curOrnament.GetLoopLimit()) { dst.PosInOrnament = curOrnament.GetLoop(); } }
void GetNewChannelState(const Cell& src, ChannelState& dst, AYM::TrackBuilder& track) { if (const bool* enabled = src.GetEnabled()) { dst.Enabled = *enabled; } dst.VolSlideCounter = 0; dst.SlidingSteps = 0; bool contSample = false, contOrnament = false; bool reloadNote = false; for (CommandsIterator it = src.GetCommands(); it; ++it) { switch (it->Type) { case ENVELOPE: if (-1 != it->Param1) { track.SetEnvelopeType(it->Param1); } if (-1 != it->Param2) { EnvelopeTone = it->Param2; track.SetEnvelopeTone(EnvelopeTone); } break; case ENVELOPE_ON: dst.Envelope = true; break; case ENVELOPE_OFF: dst.Envelope = false; break; case NOISE: dst.BaseNoise = it->Param1; break; case CONT_SAMPLE: contSample = true; break; case CONT_ORNAMENT: contOrnament = true; break; case GLISS: dst.Glissade = it->Param1; dst.SlidingSteps = -1;//infinite sliding break; case SLIDE: { dst.SlidingSteps = it->Param1; const int_t newSliding = (dst.Sliding | 0xf) ^ 0xf; dst.Glissade = -newSliding / (dst.SlidingSteps ? dst.SlidingSteps : 1); dst.Sliding = dst.Glissade * dst.SlidingSteps; break; } case SLIDE_NOTE: { dst.SlidingSteps = it->Param1; dst.SlidingTargetNote = it->Param2; const int_t absoluteSliding = track.GetSlidingDifference(dst.Note, dst.SlidingTargetNote); const int_t newSliding = absoluteSliding - (contSample ? dst.Sliding / 16 : 0); dst.Glissade = 16 * newSliding / (dst.SlidingSteps ? dst.SlidingSteps : 1); reloadNote = true; break; } case AMPLITUDE_SLIDE: dst.VolSlideCounter = dst.VolSlideDelay = it->Param1; dst.VolSlideAddon = it->Param2; break; case BREAK_SAMPLE: dst.BreakSample = true; break; default: assert(!"Invalid cmd"); break; } } if (const uint_t* ornament = src.GetOrnament()) { dst.OrnamentNum = *ornament; } if (const uint_t* sample = src.GetSample()) { dst.SampleNum = *sample; } if (const uint_t* note = src.GetNote()) { dst.Note = *note; reloadNote = true; } if (reloadNote) { dst.CurrentNoise = dst.BaseNoise; if (dst.SlidingSteps <= 0) { dst.Sliding = 0; } if (!contSample) { dst.CurrentSampleNum = dst.SampleNum; dst.PosInSample = 0; dst.VolumeAddon = 0; dst.ToneDeviation = 0; dst.BreakSample = false; } if (!contOrnament) { dst.CurrentOrnamentNum = dst.OrnamentNum; dst.PosInOrnament = 0; dst.NoteAddon = 0; } } if (const uint_t* volume = src.GetVolume()) { dst.Volume = *volume; } }
void GetNewChannelState(const Cell& src, ChannelState& dst, AYM::TrackBuilder& track) { if (const bool* enabled = src.GetEnabled()) { dst.Enabled = *enabled; if (!dst.Enabled) { dst.Sliding = dst.Glissade = 0; dst.SlidingTargetNote = LIMITER; } dst.PosInSample = dst.PosInOrnament = 0; } if (const uint_t* note = src.GetNote()) { assert(src.GetEnabled()); dst.Note = *note; dst.Sliding = dst.Glissade = 0; dst.SlidingTargetNote = LIMITER; } if (const uint_t* sample = src.GetSample()) { dst.SampleNum = *sample; dst.PosInSample = 0; } if (const uint_t* ornament = src.GetOrnament()) { dst.OrnamentNum = *ornament; dst.PosInOrnament = 0; } if (const uint_t* volume = src.GetVolume()) { dst.Volume = *volume; } for (CommandsIterator it = src.GetCommands(); it; ++it) { switch (it->Type) { case ENVELOPE: track.SetEnvelopeType(it->Param1); track.SetEnvelopeTone(it->Param2); dst.Envelope = true; break; case NOENVELOPE: dst.Envelope = false; break; case NOISE_ADD: dst.NoiseAdd = it->Param1; break; case GLISS_NOTE: dst.Sliding = 0; dst.Glissade = it->Param1; dst.SlidingTargetNote = it->Param2; break; case GLISS: dst.Glissade = it->Param1; dst.SlidingTargetNote = LIMITER; break; case NOGLISS: dst.Glissade = 0; break; default: assert(!"Invalid command"); } } }