int GMSynthDLL::ThreadProc() { if (live) { if (seqMode & seqPlay) ldTm = 0.02; else ldTm = 0.20; OpenWaveDevice(); inmgr.SetWaveOut(&wvd); } else { if (wvf.OpenWaveFile(outFileName, 2)) { OnEvent(SEQEVT_SEQSTOP, NULL); return GMSYNTH_ERR_FILEOPEN; } inmgr.SetWaveOut(&wvf); } inmgr.Reset(); seq.SequenceMulti(inmgr, stTime, endTime, seqMode); if (live) { bsInt32 drain = (bsInt32) (synthParams.sampleRate * (ldTm * 4)); while (--drain > 0) inmgr.Tick(); CloseWaveDevice(); } else wvf.CloseWaveFile(); return GMSYNTH_NOERROR; }
LRESULT CMainDlg::OnSaveWave(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { char fileName[MAX_PATH]; memset(fileName, 0, sizeof(fileName)); OPENFILENAME ofn; memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = "Sound Files(*.wav)\0*.wav\0All Files(*.*)\0*.*\0"; ofn.nFilterIndex = 1; ofn.lpstrFile = fileName; ofn.lpstrDefExt = ".wav"; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_OVERWRITEPROMPT; if (GetSaveFileName (&ofn)) { double frq = GetFrequency(); GenWaveI wv; wv.InitWT(frq, WT_USR(0)); EnvGen eg; eg.InitEG(1.0, 2.0, 0.05, 0.05); WaveFile wvf; wvf.OpenWaveFile(fileName, 2); long totalSamples = (long) (2.0 * synthParams.sampleRate); for (long n = 0; n < totalSamples; n++) wvf.Output1(eg.Gen() * wv.Gen()); wvf.CloseWaveFile(); } return 0; }
LRESULT CMainDlg::OnSave(WORD /*wNotifyCode*/, WORD wID, HWND /*hWndCtl*/, BOOL& /*bHandled*/) { char fileName[MAX_PATH]; memset(fileName, 0, sizeof(fileName)); OPENFILENAME ofn; memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(ofn); ofn.hwndOwner = m_hWnd; ofn.lpstrFilter = "Sound Files(*.wav)\0*.wav\0All Files(*.*)\0*.*\0"; ofn.nFilterIndex = 1; ofn.lpstrFile = fileName; ofn.lpstrDefExt = ".wav"; ofn.nMaxFile = MAX_PATH; ofn.Flags = OFN_OVERWRITEPROMPT; if (GetSaveFileName (&ofn)) { WaveFile wvf; wvf.OpenWaveFile(fileName, 2); InitGen(); long totalSamples = (long) ((durTotal * synthParams.sampleRate) + 0.5); long atkSamples = (long) (durAtkSus * synthParams.sampleRate); long n; for (n = 0; n < atkSamples; n++) wvf.Output1(Generate()); NoteOff(); while (n++ < totalSamples) wvf.Output1(Generate()); for (n = 0; n < 440; n++) wvf.Output1(0); wvf.CloseWaveFile(); } return 0; }
int main(int argc, char *argv[]) { #if defined(USE_MSXML) CoInitialize(0); #endif const char *fname = "data.xml"; if (argc > 1) fname = argv[1]; InitSynthesizer(); mix.SetChannels(2); mix.MasterVolume(1.0, 1.0); mix.ChannelOn(0, 1); mix.ChannelOn(1, 1); mix.ChannelVolume(0, 1.0); mix.ChannelVolume(1, 1.0); #ifdef ADD_REVERB mix.SetFxChannels(1); mix.FxInit(0, &rvrb, 0.1); mix.FxLevel(0, 0, 0.2); mix.FxLevel(0, 1, 0.2); rvrb.InitReverb(1.0, 2.0); #endif inMgr.Init(&mix, &wvf); inMgr.AddType("Tone", ToneInstr::ToneFactory, ToneInstr::ToneEventFactory); inMgr.AddType("ToneFM", ToneFM::ToneFMFactory, ToneFM::ToneFMEventFactory); inMgr.AddType("AddSynth", AddSynth::AddSynthFactory, AddSynth::AddSynthEventFactory); inMgr.AddType("SubSynth", SubSynth::SubSynthFactory, SubSynth::SubSynthEventFactory); inMgr.AddType("FMSynth", FMSynth::FMSynthFactory, FMSynth::FMSynthEventFactory); inMgr.AddType("MatrixSynth", MatrixSynth::MatrixSynthFactory, MatrixSynth::MatrixSynthEventFactory); inMgr.AddType("WFSynth", WFSynth::WFSynthFactory, WFSynth::WFSynthEventFactory); inMgr.AddType("Chuffer", Chuffer::ChufferFactory, Chuffer::ChufferEventFactory); inMgr.AddType("ModSynth", ModSynth::ModSynthFactory, ModSynth::ModSynthEventFactory); inMgr.AddType("BuzzSynth", BuzzSynth::InstrFactory, BuzzSynth::EventFactory); InstrMapEntry *ime = 0; while ((ime = inMgr.EnumType(ime)) != 0) ime->dumpTmplt = DestroyTemplate; XmlSynthDoc doc; XmlSynthElem rootNode(&doc); if (!doc.Open(fname, &rootNode)) { printf("Cannot open file %s\n", fname); exit(1); } // Optional: use LoadInstrLib(inMgr, fname) // but we want to discover the inum values // and add sequences programaticaly... XmlSynthElem elem(&doc); XmlSynthElem *inst = rootNode.FirstChild(&elem); while (inst != NULL) { if (inst->TagMatch("instr")) { InstrConfig *ent = inMgr.LoadInstr(inst); if (strcmp(ent->instrType->GetType(), "WFSynth") == 0) AddEvent(ent->inum, 48, 1.0); else AddSequence(ent->inum, 0.25); } inst = elem.NextSibling(&elem); } doc.Close(); if (wvf.OpenWaveFile("example10.wav", 2)) { printf("Cannot open wavefile for output\n"); exit(1); } seq.Sequence(inMgr); #ifdef ADD_REVERB // drain the reverb... AmpValue lv; AmpValue rv; long n = synthParams.isampleRate; while (n-- > 0) { mix.Out(&lv, &rv); wvf.Output2(lv, rv); } #endif wvf.CloseWaveFile(); /////////////////////////////////////////////////////////////// // Code to test instrument save functions... #define TEST_SAVE_INSTR 1 #ifdef TEST_SAVE_INSTR doc.NewDoc("instrlib", &rootNode); InstrConfig *inc = inMgr.EnumInstr(0); while (inc) { InstrMapEntry *ime = inc->instrType; Instrument *ip = (Instrument *)inc->instrTmplt; if (ip) { rootNode.AddChild("instr", &elem); elem.SetAttribute("id", inc->inum); elem.SetAttribute("type", ime->itype); elem.SetAttribute("name", inc->GetName()); elem.SetAttribute("desc", inc->GetDesc()); ip->Save(&elem); } inc = inMgr.EnumInstr(inc); } bsString outxml(fname); bsString outbase; bsString outfile; outxml.SplitPath(outbase, outfile, 1); outxml = outbase; outxml += '_'; outxml += outfile; doc.Save(outxml); #endif /////////////////////////////////////////////////////////////// return 0; }
int main(int argc, char *argv[]) { int pitch = 48; // middle C FrqValue duration = 1.0; AmpValue lfoAmp = 10; bsInt32 tl = 16384; if (argc > 1) duration = atof(argv[1]); if (argc > 2) pitch = atoi(argv[2]); if (argc > 3) tl = atol(argv[3]); InitSynthesizer(44100, tl); FrqValue frequency = synthParams.GetFrequency(pitch); if (wvf.OpenWaveFile("example04.wav", 1) < 0) { printf("Cannot open wavefile for output\n"); exit(1); } //EnvGen eg; EnvGenExp eg; //EnvGenLog eg; eg.SetBias(0.2); eg.InitEG(0.7, duration, 0.2, 0.3); GenWaveWT wv; GenWaveI wvi; GenWave32 wv32; //GenWave64 wv64; GenWaveFM wvfm; GenWaveAM wvam; GenWaveRM wvrm; ///////////////////////////////////////////////// // 1 - sine wave ///////////////////////////////////////////////// wv.InitWT(frequency, WT_SIN); Generate(duration, &wv, &eg); //GenerateVib(duration, &wv, &eg, lfoAmp); //GeneratePhaseVib(duration, &wv, &eg, lfoAmp); ///////////////////////////////////////////////// // 2 - sine wave using interpolation ///////////////////////////////////////////////// wvi.InitWT(frequency, WT_SIN); Generate(duration, &wvi, &eg); //GenerateVib(duration, &wvi, &eg, lfoAmp); //GeneratePhaseVib(duration, &wvi, &eg, lfoAmp); Silence(0.25); ///////////////////////////////////////////////// // 3 - fixed summation of sine waves ///////////////////////////////////////////////// wv.InitWT(frequency, WT_SAW); Generate(duration, &wv, &eg); //GenerateVib(duration, &wv, &eg, lfoAmp); //GeneratePhaseVib(duration, &wv, &eg, lfoAmp); ///////////////////////////////////////////////// // 4 - fixed summation of sine waves using interpolation ///////////////////////////////////////////////// wvi.InitWT(frequency, WT_SAW); Generate(duration, &wvi, &eg); //GenerateVib(duration, &wvi, &eg, lfoAmp); //GeneratePhaseVib(duration, &wvi, &eg, lfoAmp); ///////////////////////////////////////////////// // 5 - 32 bit fixed-point index, ///////////////////////////////////////////////// wv32.InitWT(frequency, WT_SAW); Generate(duration, &wv32, &eg); //GenerateVib(duration, &wv32, &eg, lfoAmp); //GeneratePhaseVib(duration, &wv32, &eg, lfoAmp); ///////////////////////////////////////////////// // 6 - 64 bit fixed-point index, ///////////////////////////////////////////////// //wv64.InitWT(frequency, WT_SAW); //Generate(duration, &wv64, &eg); //GenerateVib(duration, &wv64, &eg, lfoAmp); //GeneratePhaseVib(duration, &wv64, &eg, lfoAmp); Silence(0.25); ///////////////////////////////////////////////// // 7 - square wave (summation) ///////////////////////////////////////////////// wv.InitWT(frequency, WT_SQR); Generate(duration, &wv, &eg); //GenerateVib(duration, &wv, &eg, lfoAmp); //GeneratePhaseVib(duration, &wv, &eg, lfoAmp); ///////////////////////////////////////////////// // 8 - triangle wave (summation) ///////////////////////////////////////////////// wv.InitWT(frequency, WT_TRI); Generate(duration, &wv, &eg); Silence(0.25); ///////////////////////////////////////////////// // 9 - FM ///////////////////////////////////////////////// wvfm.InitFM(frequency/2, 2.0, 1.0, WT_SIN); Generate(duration, &wvfm, &eg); wvfm.InitFM(frequency, 2.0, 1.0, WT_SIN); Generate(duration, &wvfm, &eg); //GenerateVib(duration, &wvfm, &eg, lfoAmp); //GeneratePhaseVib(duration, &wvfm, &eg, lfoAmp); Silence(0.25); ///////////////////////////////////////////////// // 10 - Amplitude Modulation ///////////////////////////////////////////////// wvam.InitAM(frequency, frequency*2.5, 1.0, WT_SIN); Generate(duration, &wvam, &eg); ///////////////////////////////////////////////// // 11 - Ring Modulation ///////////////////////////////////////////////// wvrm.InitAM(frequency, frequency*2.5, 1.0, WT_SIN); Generate(duration, &wvrm, &eg); Silence(0.25); ///////////////////////////////////////////////// // 12 - Dynamic summing: sawtooth ///////////////////////////////////////////////// GenWaveSum wvs; AmpValue mult[8]; AmpValue amps[8]; for (int pnum = 0; pnum < 8; pnum++) { AmpValue x = (AmpValue)pnum + 1; mult[pnum] = x; amps[pnum] = 1.0/x; if (pnum & 1) amps[pnum] = -amps[pnum]; } wvs.InitParts(8, mult, amps, 1); wvs.InitWT(frequency, WT_SIN); Generate(duration, &wvs, &eg); //GenerateVib(duration, &wvs, &eg, lfoAmp); //GeneratePhaseVib(duration, &wvs, &eg, lfoAmp); ///////////////////////////////////////////////// // 13 - Dynamic summing: doubling at the fifth ///////////////////////////////////////////////// mult[0] = 1.0f; mult[1] = 1.5f; amps[0] = 0.5f; amps[1] = 0.5f; wvs.InitParts(2, mult, amps, 0); wvs.InitWT(frequency, WT_SAW); Generate(duration, &wvs, &eg); //GenerateVib(duration, &wvs, &eg, lfoAmp); ///////////////////////////////////////////////// // 14 - Dynamic summing: chorus effect, two notes at slightly different frequency ///////////////////////////////////////////////// mult[0] = 1.0; mult[1] = 1.001; amps[0] = 0.6; amps[1] = 0.4; wvs.InitParts(2, mult, amps, 0); wvs.InitWT(frequency, WT_SAW); Generate(duration, &wvs, &eg); //GenerateVib(duration, &wvs, &eg, lfoAmp); Silence(0.25); // For comparison: ///////////////////////////////////////////////// // 15 - Sine wave Direct ///////////////////////////////////////////////// GenWave wvsin; wvsin.Init(1, &frequency); Generate(duration, &wvsin, &eg); //GenerateVib(duration, &wvsin, &eg, lfoAmp); ///////////////////////////////////////////////// // 16 - Sawtooth Direct ///////////////////////////////////////////////// GenWaveSaw wvsaw; wvsaw.Init(1, &frequency); Generate(duration, &wvsaw, &eg); //GenerateVib(duration, &wvsaw, &eg, lfoAmp); //GeneratePhaseVib(duration, &wvsaw, &eg, lfoAmp); ///////////////////////////////////////////////// // 17 - Triangle Direct ///////////////////////////////////////////////// GenWaveTri wvtri; wvtri.Init(1, &frequency); Generate(duration, &wvtri, &eg); //GenerateVib(duration, &wvtri, &eg, lfoAmp); //GeneratePhaseVib(duration, &wvtri, &eg, lfoAmp); ///////////////////////////////////////////////// // 18 - Square Direct ///////////////////////////////////////////////// GenWaveSqr wvsqr; wvsqr.InitSqr(frequency, 50.0); Generate(duration, &wvsqr, &eg); //GenerateVib(duration, &wvsqr, &eg, lfoAmp); //GeneratePhaseVib(duration, &wvsqr, &eg, lfoAmp); ///////////////////////////////////////////////// // 19 - Square Direct Integer ///////////////////////////////////////////////// GenWaveSqr32 wvsqr32; wvsqr32.InitSqr(frequency, 50.0); Generate(duration, &wvsqr32, &eg); Silence(0.25); ///////////////////////////////////////////////// // 20 - White Noise ///////////////////////////////////////////////// GenNoise wvn; Generate(duration, &wvn, &eg); ///////////////////////////////////////////////// // 21 - 'H' White Noise (sampled) ///////////////////////////////////////////////// GenNoiseH wvnh; float h; for (h = 2000.0; h < 10000.0; h += 2000.0) { wvnh.Init(1, &h); Generate(duration, &wvnh, &eg); } ///////////////////////////////////////////////// // 21 - 'Interploated' White Noise ///////////////////////////////////////////////// GenNoiseI wvni; for (h = 2000.0; h < 10000.0; h += 2000.0) { wvni.Init(1, &h); Generate(duration, &wvni, &eg); } Silence(0.25); ///////////////////////////////////////////////// // 22 - "Pink-ish" Noise (FIR filter) ///////////////////////////////////////////////// GenNoisePink1 wvp1; Generate(duration, &wvp1, &eg); ///////////////////////////////////////////////// // 23 - "Pink-ish" Noise (IIR filter) ///////////////////////////////////////////////// GenNoisePink2 wvp2; Generate(duration, &wvp2, &eg); Silence(0.25); ///////////////////////////////////////////////// // 23 - Pitched Noise (ring modulation of sine wave and noise) ///////////////////////////////////////////////// GenWaveNZ wvnzp; wvnzp.InitNZ(500.0, 400.0, WT_SIN); Generate(duration, &wvnzp, &eg); wvnzp.InitNZ(800.0, 400.0, WT_SIN); Generate(duration, &wvnzp, &eg); Silence(0.25); ///////////////////////////////////////////////// // 24 - BUZZ generator ///////////////////////////////////////////////// GenWaveBuzz buzz; buzz.InitBuzz(frequency, 20); Generate(duration, &buzz, &eg); buzz.InitBuzz(frequency, 100); Generate(duration, &buzz, &eg); // buzz.InitBuzz(frequency, 100); // GenerateVib(duration, &buzz, &eg, lfoAmp); // GeneratePhaseVib(duration, &buzz, &eg, lfoAmp); Silence(0.25); GenWaveBuzz2 buzz2; buzz2.InitBuzz(frequency, 20); Generate(duration, &buzz2, &eg); buzz2.InitBuzz(frequency, 100); Generate(duration, &buzz2, &eg); Silence(0.25); GenWaveBuzzA buzza; // buzza.SetOscillatorA(new GenWaveI); // buzza.SetOscillatorB(new GenWaveI); buzza.InitBuzz(frequency, 20); Generate(duration, &buzza, &eg); buzza.InitBuzz(frequency, 100); Generate(duration, &buzza, &eg); Silence(0.25); GenWaveDS ds; ds.InitDS(frequency, 0.5); Generate(duration, &ds, &eg); ds.InitDS(frequency, 0.95); Generate(duration, &ds, &eg); Silence(0.25); GenWaveDSB gbz; gbz.InitDSB(frequency, 1, 100, 0.5); Generate(duration, &gbz, &eg); gbz.InitDSB(frequency, 1, 100, 0.95); Generate(duration, &gbz, &eg); // Odd harmonics, like square wave gbz.InitDSB(frequency, 2, 100, 0.5); Generate(duration, &gbz, &eg); gbz.InitDSB(frequency, 2, 100, 0.95); Generate(duration, &gbz, &eg); ///////////////////////////////////////////////// if (wvf.CloseWaveFile()) perror("Close"); return 0; }
int main(int argc, char *argv[]) { InitSynthesizer(); long n; int pitch = 48; FrqValue duration = 2.75; AmpValue value1, value2; if (argc > 1) duration = atof(argv[1]); if (argc > 2) pitch = atoi(argv[2]); FrqValue frequency = synthParams.GetFrequency(pitch); if (wvf.OpenWaveFile("example07b.wav", 2)) { printf("Cannot open wavefile for output\n"); exit(1); } GenWaveFM wv; wv.InitFM(frequency, 1, 2, WT_SIN); EnvGen eg; eg.InitEG(0.5f, duration, 0.5f, 0.5f); long totalSamples = (long) ((duration * synthParams.sampleRate) + 0.5); // reference sound. for (n = 0; n < totalSamples; n++) { value2 = (eg.Gen() * wv.Gen()); wvf.Output1(value2); } Silence(0.25); // Flanger #1 varies from 0 to 5ms Flanger flng1; flng1.InitFlanger(0.5, 0.5, 0, 0.0025, 0.005, 0.15); // Flanger #2 varies from 45 to 50ms Flanger flng2; flng2.InitFlanger(0.5, 0.5, 0, 0.0042, 0.005, 0.15); // Flanger #3 is set for a chorus effect Flanger flng3; flng3.InitFlanger(0.5, 0.5, 0.5, 0.100, 0.001, 0.8); for (float snd = 0.5; snd <= 1; snd += 0.5) { wv.InitFM(frequency*snd, 1, 2, WT_SIN); eg.Reset(); flng1.Clear(); for (n = 0; n < totalSamples; n++) { value1 = (eg.Gen() * wv.Gen()); value2 = flng1.Sample(value1); wvf.Output2(value2, value2); } Silence(0.25); eg.Reset(); flng2.Clear(); for (n = 0; n < totalSamples; n++) { value1 = (eg.Gen() * wv.Gen()); value2 = flng2.Sample(value1); wvf.Output2(value2, value2); } Silence(0.25); eg.Reset(); flng3.Clear(); for (n = 0; n < totalSamples; n++) { value1 = (eg.Gen() * wv.Gen()); value2 = flng3.Sample(value1); wvf.Output2(value2, value2); } Silence(0.25); } wvf.CloseWaveFile(); return 0; }
int main(int argc, char *argv[]) { int pitch = 48; // Middle C FrqValue duration = 1; AmpValue peakAmp = 1; if (argc > 1) duration = atof(argv[1]); if (argc > 2) pitch = atoi(argv[2]); if (argc > 3) peakAmp = atof(argv[3]); InitSynthesizer(); FrqValue frequency = synthParams.GetFrequency(pitch); PhsAccum phaseIncr = synthParams.frqRad * frequency; PhsAccum phase = 0; long silence = (long) (synthParams.sampleRate * 0.1); long totalSamples = (long) ((synthParams.sampleRate * duration) + 0.5); long attackTime = (long) (0.2 * synthParams.sampleRate); long decayTime = (long) (0.4 * synthParams.sampleRate); long sustainTime = totalSamples - (attackTime + decayTime); long decayStart = totalSamples - decayTime; AmpValue envInc = peakAmp / (float) attackTime; AmpValue volume = 0; long n; WaveFile wf; if (wf.OpenWaveFile("example02.wav", 1)) { printf("Cannot open wavefile for output\n"); exit(1); } ///////////////////////////////////////////////// // Method 1 - simple integration, linear ///////////////////////////////////////////////// long sampleNumber = 0; for (n = 0; n < totalSamples; n++) { if (n < attackTime || n > decayStart) volume += envInc; else if (n == attackTime) volume = peakAmp; else if (n == decayStart) envInc = -volume / (float) decayTime; wf.Output1(volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); ///////////////////////////////////////////////// // Method 1 - convex exponential (n^2) ///////////////////////////////////////////////// sampleNumber = 0; volume = 0; phase = 0; envInc = peakAmp / (float) attackTime; for (n = 0; n < totalSamples; n++) { if (n < attackTime || n > decayStart) volume += envInc; else if (n == attackTime) volume = peakAmp; else if (n == decayStart) envInc = -volume / (float) decayTime; wf.Output1(volume * volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); ///////////////////////////////////////////////// // Method 1 - variable exponential ///////////////////////////////////////////////// phase = 0; volume = 0; float expMin = 0.2; float expMax = 1.0+expMin; float expNow = expMin; float expMul = pow(expMax/expMin, 1.0f / (float) attackTime); for (n = 0; n < totalSamples; n++) { if (n < attackTime || n > decayStart) { expNow *= expMul; volume = (expNow - expMin) * peakAmp; } else if (n == attackTime) { volume = peakAmp; expNow = expMax; } else if (n == decayStart) { expMul = pow(expMin/expMax, 1.0f / (float) decayTime); } wf.Output1(volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0.0); ///////////////////////////////////////////////// // Method 1 - log ///////////////////////////////////////////////// phase = 0; volume = 0; expNow = expMax; expMul = pow(expMin/expMax, 1.0f / (float) attackTime); for (n = 0; n < totalSamples; n++) { if (n < attackTime || n > decayStart) { expNow *= expMul; volume = (1.0f - (expNow - expMin)) * peakAmp; } else if (n == attackTime) { volume = peakAmp; expNow = expMin; } else if (n == decayStart) expMul = pow(expMax/expMin, 1.0f / (float) decayTime); wf.Output1(volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); ///////////////////////////////////////////////// // Method 1 - dB ///////////////////////////////////////////////// phase = 0; volume = 0; float dbLevel = -96; float dbIncr = 96.0 / attackTime; for (n = 0; n < totalSamples; n++) { if (n < attackTime || n > decayStart) { dbLevel += dbIncr; volume = pow(10.0, dbLevel / 20.0); } else if (n == attackTime) { volume = 1.0; dbLevel = 0.0; } else if (n == decayStart) { dbIncr = -96.0 / decayTime; } wf.Output1(peakAmp * volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); ///////////////////////////////////////////////// // Method 2 - simple state machine ///////////////////////////////////////////////// long envCount = attackTime; int envState = 0; envInc = peakAmp / (float) attackTime; phase = 0; volume = 0; for (n = 0; n < totalSamples; n++) { switch (envState) { case 0: if (envCount > 0) { volume += envInc; envCount--; } else { volume = peakAmp; envCount = sustainTime; envState = 1; } break; case 1: if (envCount > 0) envCount--; else { envCount = decayTime; envInc = volume / (float) decayTime; envState = 2; } break; case 2: if (envCount > 0) { volume -= envInc; envCount--; } else { volume = 0; envState = 3; } break; case 3: break; } wf.Output1(volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); ///////////////////////////////////////////////// // Method 3 - multiple segments (ADSR) ///////////////////////////////////////////////// float envPeak; float envStep; float envLevel[4]; float envIncr[4]; long envTime[4]; int maxEnvIndex = 4; int envIndex = -1; envLevel[0] = 1.0 * peakAmp; envLevel[1] = 0.7 * peakAmp; envLevel[2] = 0.7 * peakAmp; envLevel[3] = 0.0; envTime[0] = (long) (0.1 * synthParams.sampleRate); envTime[1] = (long) (0.2 * synthParams.sampleRate); envTime[2] = (long) (0.5 * synthParams.sampleRate); envTime[3] = (long) (0.2 * synthParams.sampleRate); // pre-calculate increments envIncr[0] = envLevel[0] / envTime[0]; for (n = 1; n < maxEnvIndex; n++) { if (envTime[n] > 0) envIncr[n] = (envLevel[n] - envLevel[n-1]) / envTime[n]; else envIncr[n] = (envLevel[n] - envLevel[n-1]); } phase = 0; volume = 0; envCount = 0; envPeak = 0; envStep = 0; for (n = 0; n < totalSamples; n++) { if (--envCount <= 0) { volume = envPeak; if (++envIndex < maxEnvIndex) { envCount = envTime[envIndex]; envStep = envIncr[envIndex]; envPeak = envLevel[envIndex]; } else envStep = 0; } else { volume += envStep; } wf.Output1(volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); ///////////////////////////////////////////////// // Method 4 - multiple segments state machine ///////////////////////////////////////////////// float atkLevel[2]; float decLevel[2]; long atkTime[2]; long decTime[2]; long atkMaxIndex = 2; long decMaxIndex = 2; atkLevel[0] = 1.0 * peakAmp; atkLevel[1] = 0.7 * peakAmp; decLevel[0] = 0.2 * peakAmp; decLevel[1] = 0.0; atkTime[0] = (long) (0.1 * synthParams.sampleRate); atkTime[1] = (long) (0.2 * synthParams.sampleRate); decTime[0] = (long) (0.1 * synthParams.sampleRate); decTime[1] = (long) (0.2 * synthParams.sampleRate); sustainTime = totalSamples - (atkTime[0] + atkTime[1] + decTime[0] + decTime[1]); phase = 0; volume = 0; envCount = 0; envIndex = -1; envState = 0; envPeak = 0; for (n = 0; n < totalSamples; n++) { switch (envState) { case 0: // attack if (--envCount <= 0) { volume = envPeak; if (++envIndex < atkMaxIndex) { envPeak = atkLevel[envIndex]; envCount = atkTime[envIndex]; if (envCount < 1) envCount = 1; envStep = (envPeak - volume) / envCount; } else { envCount = sustainTime; envStep = 0.0; envState = 1; } } else volume += envStep; break; case 1: // sustain if (--envCount <= 0) { envIndex = -1; envState = 2; } break; case 2: // release if (--envCount <= 0) { volume = envPeak; if (++envIndex < decMaxIndex) { envPeak = decLevel[envIndex]; envCount = decTime[envIndex]; if (envCount < 1) envCount = 1; envStep = (envPeak - volume) / envCount; } else { envCount = 0; envStep = 0.0; volume = 0.0; envState = 3; } } else volume += envStep; break; case 3: break; } wf.Output1(volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); ///////////////////////////////////////////////// // Method 5 - constant rate ADSR ///////////////////////////////////////////////// phase = 0; volume = 0; envState = 0; float sustainAmpCR = 0.8; float atkTimeCR = 0.1; float decTimeCR = 0.5; float relTimeCR = 0.5; float atkIncrCR = 1.0 / (atkTimeCR * synthParams.sampleRate); float decIncrCR = 1.0 / (decTimeCR * synthParams.sampleRate); float relIncrCR = 1.0 / (relTimeCR * synthParams.sampleRate); float susTimeCR = 0; for (n = 0; n < totalSamples; n++) { switch (envState) { case 0: if ((volume += atkIncrCR) >= 1.0) { volume = 1.0; envState = 1; } break; case 1: if ((volume -= decIncrCR) <= sustainAmpCR) { volume = sustainAmpCR; envState = 2; // for testing. This type envelope would normally sustain until release signal. susTimeCR = totalSamples - n - ((relTimeCR * synthParams.sampleRate) * sustainAmpCR); } break; case 2: if (--susTimeCR <= 0) envState = 3; break; case 3: if ((volume -= decIncrCR) <= 0) { volume = 0; envState = 4; } break; } wf.Output1(volume * volume * sinv(phase)); // convex curve //wf.Output1(volume * sinv(phase)); // linear if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); ///////////////////////////////////////////////// // Method 5 - constant rate ADSR, transformed ///////////////////////////////////////////////// float envTblLen = 960; // 96 dB range float envTblNdx = 0; float atkTblCR[960]; float decTblCR[960]; atkTblCR[0] = 0.0; decTblCR[0] = 0.0; for (n = 1; n < envTblLen; n++) { volume = pow(10, (double)(959 - n) / -200.0); atkTblCR[n] = volume; decTblCR[n] = volume; } sustainAmpCR = 0.5; atkIncrCR = 960.0 / (atkTimeCR * synthParams.sampleRate); decIncrCR = 960.0 / (decTimeCR * synthParams.sampleRate); relIncrCR = 960.0 / (relTimeCR * synthParams.sampleRate); susTimeCR = totalSamples - ((relTimeCR * synthParams.sampleRate) * sustainAmpCR); phase = 0; volume = 0; envState = 0; for (n = 0; n < totalSamples; n++) { switch (envState) { case 0: if ((envTblNdx += atkIncrCR) >= envTblLen) { envTblNdx = envTblLen-1; envState = 1; } volume = atkTblCR[(int)envTblNdx]; break; case 1: if ((envTblNdx -= decIncrCR) < 0) envTblNdx = 0; volume = decTblCR[(int)envTblNdx]; if (volume <= sustainAmpCR) { volume = sustainAmpCR; envState = 2; susTimeCR = totalSamples - n - ((relTimeCR * synthParams.sampleRate) * sustainAmpCR); } break; case 2: if (--susTimeCR <= 0) envState = 3; break; case 3: if ((envTblNdx -= decIncrCR) <= 0) { envTblNdx = 0; envState = 4; } volume = decTblCR[(int)envTblNdx]; break; } wf.Output1(volume * sinv(phase)); if ((phase += phaseIncr) >= twoPI) phase -= twoPI; } for (n = 0; n < silence; n++) wf.Output1(0); wf.CloseWaveFile(); int oor = wf.GetOOR(); if (oor) printf("%d Samples out of range...\n", oor); return 0; }