/* build a new note object with all parameters determined. *StartAdjustOut */ /* indicates how many ticks before (negative) or after (positive) now that */ /* the key-down should occur. this is added to the scanning gap size and envelope */ /* origins to figure out how to schedule the note */ public static void FixNoteParameters( IncrParamUpdateRec GlobalParamSource, NoteNoteObjectRec Note, out int StartAdjustOut, double EnvelopeTicksPerDurationTick, short PitchIndexAdjust, ref FrozenNoteRec FrozenNote, SynthParamRec SynthParams) { // must assign all fields /* reference to the note that defines this note. */ FrozenNote.OriginalNote = Note; /* frequency determined by pitch index + detuning, in Hertz */ double NominalFrequency; { int i = Note._Pitch + GlobalParamSource.TransposeHalfsteps + PitchIndexAdjust; if (i < 0) { i = 0; } else if (i > Constants.NUMNOTES - 1) { i = Constants.NUMNOTES - 1; } /* compute frequency from index */ #if DEBUG if ((Constants.CENTERNOTE % 12) != 0) { // CENTERNOTE multiple of 12 Debug.Assert(false); throw new ArgumentException(); } #endif double d = GlobalParamSource.FrequencyTable[i % 12].nd.Current; i = (i / 12) - (Constants.CENTERNOTE / 12); d = d * Math.Exp(i * Constants.LOG2) * Constants.MIDDLEC; /* apply detuning */ double e; switch (Note.Flags & NoteFlags.eDetuningModeMask) { default: Debug.Assert(false); throw new ArgumentException(); case NoteFlags.eDetuningModeDefault: e = (double)Note._Detuning * GlobalParamSource.Detune.nd.Current; if (GlobalParamSource.DetuneHertz) { goto DetuneHertzPoint; } else { goto DetuneHalfStepsPoint; } case NoteFlags.eDetuningModeHalfSteps: e = (double)(Note._Detuning) + GlobalParamSource.Detune.nd.Current; DetuneHalfStepsPoint: NominalFrequency = d * Math.Exp((e / 12) * Constants.LOG2); break; case NoteFlags.eDetuningModeHertz: e = (double)Note._Detuning + GlobalParamSource.Detune.nd.Current; DetuneHertzPoint: NominalFrequency = d + e; break; } } FrozenNote.NominalFrequency = NominalFrequency; /* frequency used for doing multisampling, in Hertz */ if (Note._MultisamplePitchAsIf != -1) { /* compute frequency from index */ int i = Note._MultisamplePitchAsIf; #if DEBUG if ((Constants.CENTERNOTE % 12) != 0) { Debug.Assert(false); throw new ArgumentException(); } #endif double d = GlobalParamSource.FrequencyTable[i % 12].nd.Current; i = (i / 12) - (Constants.CENTERNOTE / 12); d = d * Math.Exp(i * Constants.LOG2) * Constants.MIDDLEC; FrozenNote.MultisampleFrequency = d; } else { FrozenNote.MultisampleFrequency = NominalFrequency; } /* acceleration of envelopes */ FrozenNote.HurryUpFactor = (double)Note._HurryUpFactor * GlobalParamSource.HurryUp.nd.Current; /* duration, in envelope ticks */ int Duration; { int i; switch (Note.Flags & NoteFlags.eDurationMask) { default: Debug.Assert(false); throw new ArgumentException(); case NoteFlags.e64thNote: i = DURATIONUPDATECLOCKRESOLUTION / 64; break; case NoteFlags.e32ndNote: i = DURATIONUPDATECLOCKRESOLUTION / 32; break; case NoteFlags.e16thNote: i = DURATIONUPDATECLOCKRESOLUTION / 16; break; case NoteFlags.e8thNote: i = DURATIONUPDATECLOCKRESOLUTION / 8; break; case NoteFlags.e4thNote: i = DURATIONUPDATECLOCKRESOLUTION / 4; break; case NoteFlags.e2ndNote: i = DURATIONUPDATECLOCKRESOLUTION / 2; break; case NoteFlags.eWholeNote: i = DURATIONUPDATECLOCKRESOLUTION; break; case NoteFlags.eDoubleNote: i = DURATIONUPDATECLOCKRESOLUTION * 2; break; case NoteFlags.eQuadNote: i = DURATIONUPDATECLOCKRESOLUTION * 4; break; } switch (Note.Flags & NoteFlags.eDivisionMask) { default: Debug.Assert(false); throw new ArgumentException(); case NoteFlags.eDiv1Modifier: break; case NoteFlags.eDiv3Modifier: i = i / 3; break; case NoteFlags.eDiv5Modifier: i = i / 5; break; case NoteFlags.eDiv7Modifier: i = i / 7; break; } if ((Note.Flags & NoteFlags.eDotModifier) != 0) { i = (i * 3) / 2; } double d = i; switch (Note.Flags & NoteFlags.eDurationAdjustMask) { default: Debug.Assert(false); throw new ArgumentException(); case NoteFlags.eDurationAdjustDefault: if (GlobalParamSource.DurationAdjustAdditive) { goto DurationAdjustAddPoint; } else { goto DurationAdjustMultPoint; } case NoteFlags.eDurationAdjustAdditive: DurationAdjustAddPoint: d = d + (double)Note._DurationAdjust * (DURATIONUPDATECLOCKRESOLUTION / 4); break; case NoteFlags.eDurationAdjustMultiplicative: DurationAdjustMultPoint: d = d * (double)Note._DurationAdjust; break; } if (GlobalParamSource.DurationAdjustAdditive) { d = d + GlobalParamSource.DurationAdjust.nd.Current * (DURATIONUPDATECLOCKRESOLUTION / 4); } else { d = d * GlobalParamSource.DurationAdjust.nd.Current; } /* this line is what converts from duration update ticks to envelope ticks */ Duration = (int)(d * EnvelopeTicksPerDurationTick); } FrozenNote.Duration = Duration; /* portamento duration, in envelope ticks */ FrozenNote.PortamentoDuration = (int)(((double)Note._PortamentoDuration + GlobalParamSource.Portamento.nd.Current) * (DURATIONUPDATECLOCKRESOLUTION / 4) * EnvelopeTicksPerDurationTick); /* see if portamento occurs before note retrigger */ FrozenNote.PortamentoBeforeNote = ((Note.Flags & NoteFlags.ePortamentoLeadsNote) != 0); /* first release point, in envelope ticks after start of note */ switch (Note.Flags & NoteFlags.eRelease1OriginMask) { default: Debug.Assert(false); throw new ArgumentException(); case NoteFlags.eRelease1FromStart: FrozenNote.ReleasePoint1 = (int)((double)Note._ReleasePoint1 * Duration); FrozenNote.Release1FromStart = true; break; case NoteFlags.eRelease1FromEnd: FrozenNote.ReleasePoint1 = (int)((1 - (double)Note._ReleasePoint1) * Duration); FrozenNote.Release1FromStart = false; break; case NoteFlags.eRelease1FromDefault: if (GlobalParamSource.ReleasePoint1FromStart) { FrozenNote.ReleasePoint1 = (int)(((double)Note._ReleasePoint1 + GlobalParamSource.ReleasePoint1.nd.Current) * Duration); FrozenNote.Release1FromStart = true; } else { FrozenNote.ReleasePoint1 = (int)((1 - ((double)Note._ReleasePoint1 + GlobalParamSource.ReleasePoint1.nd.Current)) * Duration); FrozenNote.Release1FromStart = false; } break; } /* second release point, in envelope ticks after start of note */ switch (Note.Flags & NoteFlags.eRelease2OriginMask) { default: Debug.Assert(false); throw new ArgumentException(); case NoteFlags.eRelease2FromStart: FrozenNote.ReleasePoint2 = (int)((double)Note._ReleasePoint2 * Duration); FrozenNote.Release2FromStart = true; break; case NoteFlags.eRelease2FromEnd: FrozenNote.ReleasePoint2 = (int)((1 - (double)Note._ReleasePoint2) * Duration); FrozenNote.Release2FromStart = false; break; case NoteFlags.eRelease2FromDefault: if (GlobalParamSource.ReleasePoint2FromStart) { FrozenNote.ReleasePoint2 = (int)(((double)Note._ReleasePoint2 + GlobalParamSource.ReleasePoint2.nd.Current) * Duration); FrozenNote.Release2FromStart = true; } else { FrozenNote.ReleasePoint2 = (int)((1 - ((double)Note._ReleasePoint2 + GlobalParamSource.ReleasePoint2.nd.Current)) * Duration); FrozenNote.Release2FromStart = false; } break; } /* third release point, in envelope ticks after start of note */ if ((Note.Flags & NoteFlags.eRelease3FromStartNotEnd) != 0) { FrozenNote.ReleasePoint3 = 0; FrozenNote.Release3FromStart = true; } else { FrozenNote.ReleasePoint3 = Duration; FrozenNote.Release3FromStart = false; } /* overall loudness adjustment for envelopes, including global volume scaling */ FrozenNote.LoudnessAdjust = (double)Note._OverallLoudnessAdjustment * GlobalParamSource.Volume.nd.Current; /* stereo positioning for note */ { double d = (double)Note._StereoPositionAdjustment + GlobalParamSource.StereoPosition.nd.Current; if (d < -1) { d = -1; } else if (d > 1) { d = 1; } FrozenNote.StereoPosition = d; } /* accent values for controlling envelopes */ InitializeAccent( ref FrozenNote.Accents, (double)Note._Accent1 + GlobalParamSource.Accent1.nd.Current, (double)Note._Accent2 + GlobalParamSource.Accent2.nd.Current, (double)Note._Accent3 + GlobalParamSource.Accent3.nd.Current, (double)Note._Accent4 + GlobalParamSource.Accent4.nd.Current, (double)Note._Accent5 + GlobalParamSource.Accent5.nd.Current, (double)Note._Accent6 + GlobalParamSource.Accent6.nd.Current, (double)Note._Accent7 + GlobalParamSource.Accent7.nd.Current, (double)Note._Accent8 + GlobalParamSource.Accent8.nd.Current); /* pitch displacement maximum depth, in tonal Hertz */ FrozenNote.PitchDisplacementDepthLimit = (double)Note._PitchDisplacementDepthAdjustment * GlobalParamSource.PitchDisplacementDepthLimit.nd.Current; /* pitch displacement maximum rate, in LFO Hertz */ FrozenNote.PitchDisplacementRateLimit = (double)Note._PitchDisplacementRateAdjustment * GlobalParamSource.PitchDisplacementRateLimit.nd.Current; /* pitch displacement start point, in envelope clocks after start of note */ switch (Note.Flags & NoteFlags.ePitchDisplacementStartOriginMask) { default: Debug.Assert(false); throw new ArgumentException(); case NoteFlags.ePitchDisplacementStartFromStart: FrozenNote.PitchDisplacementStartPoint = (int)(Duration * (double)Note._PitchDisplacementStartPoint); break; case NoteFlags.ePitchDisplacementStartFromEnd: FrozenNote.PitchDisplacementStartPoint = (int)(Duration * (1 - (double)Note._PitchDisplacementStartPoint)); break; case NoteFlags.ePitchDisplacementStartFromDefault: if (GlobalParamSource.PitchDisplacementStartPointFromStart) { FrozenNote.PitchDisplacementStartPoint = (int)(Duration * ((double)Note._PitchDisplacementStartPoint + GlobalParamSource.PitchDisplacementStartPoint.nd.Current)); } else { FrozenNote.PitchDisplacementStartPoint = (int)(Duration * (1 - ((double)Note._PitchDisplacementStartPoint + GlobalParamSource.PitchDisplacementStartPoint.nd.Current))); } break; } StartAdjustOut = (int)(((double)Note._EarlyLateAdjust + GlobalParamSource.EarlyLateAdjust.nd.Current) * Duration); }
/* construct an oscillator bank template record. various parameters are passed in */ /* which are needed for synthesis. ParameterUpdator is the parameter information */ /* record for the whole track of which this is a part. */ public static OscBankTemplateRec NewOscBankTemplate( InstrumentRec InstrumentDefinition, IncrParamUpdateRec ParameterUpdator, SynthParamRec SynthParams) { OscillatorListRec OscillatorListObject; OscBankTemplateRec Template = new OscBankTemplateRec(); /* the oscillator bank template contains all of the information needed for */ /* constructing oscillators as notes are to be executed. */ /* number of oscillators in a bank. */ OscillatorListObject = GetInstrumentOscillatorList(InstrumentDefinition); /* get LFO information */ Template.PitchLFOTemplate = GetInstrumentFrequencyLFOList(InstrumentDefinition); Template.ParamUpdator = ParameterUpdator; Template.InstrOverallLoudness = GetInstrumentOverallLoudness(InstrumentDefinition); Template.CombinedOscillatorEffects = GetInstrumentCombinedOscEffectSpecList(InstrumentDefinition); if (0 == GetEffectSpecListLength(Template.CombinedOscillatorEffects)) { /* if no effects, then set to null, so we don't do any processing */ Template.CombinedOscillatorEffects = null; } /* vector containing templates for all of the oscillators */ Template.NumOscillatorsInBank = GetOscillatorListLength(OscillatorListObject); Template.TemplateArray = new OscBankVectorRec[Template.NumOscillatorsInBank]; /* build entry for each oscillator */ for (int i = 0; i < Template.NumOscillatorsInBank; i++) { OscillatorRec Osc = GetOscillatorFromList(OscillatorListObject, i); OscBankVectorRec Osc1 = Template.TemplateArray[i] = new OscBankVectorRec(); switch (OscillatorGetWhatKindItIs(Osc)) { default: Debug.Assert(false); throw new ArgumentException(); case OscillatorTypes.eOscillatorSampled: Osc1.TemplateReference = SampleTemplateRec.NewSampleTemplate(Osc, SynthParams); break; case OscillatorTypes.eOscillatorWaveTable: Osc1.TemplateReference = WaveTableTemplateRec.NewWaveTableTemplate(Osc, SynthParams); break; case OscillatorTypes.eOscillatorFOF: Osc1.TemplateReference = FOFTemplateRec.NewFOFTemplate(Osc, SynthParams); break; case OscillatorTypes.eOscillatorAlgorithm: Osc1.TemplateReference = AlgorithmicTemplateRec.NewAlgorithmicTemplate(Osc, SynthParams); break; case OscillatorTypes.eOscillatorFMSynth: Osc1.TemplateReference = FMSynthTemplateRec.NewFMSynthTemplate(Osc, SynthParams); break; case OscillatorTypes.eOscillatorPluggable: Osc1.TemplateReference = new PluggableOscillatorTemplate(Osc, SynthParams); break; } } return(Template); }