//Requires // - Pquality.samplesize // - Pquality.basenote // - Pquality.oct // - Pquality.smpoct // - spectrum at various frequencies (oodles of data) void PADnoteParameters::sampleGenerator(PADnoteParameters::callback cb, std::function<bool()> do_abort) { const int samplesize = (((int) 1) << (Pquality.samplesize + 14)); const int spectrumsize = samplesize / 2; float *spectrum = new float[spectrumsize]; const int profilesize = 512; float profile[profilesize]; const float bwadjust = getprofile(profile, profilesize); float basefreq = 65.406f * powf(2.0f, Pquality.basenote / 2); if(Pquality.basenote % 2 == 1) basefreq *= 1.5f; int samplemax = Pquality.oct + 1; int smpoct = Pquality.smpoct; if(Pquality.smpoct == 5) smpoct = 6; if(Pquality.smpoct == 6) smpoct = 12; if(smpoct != 0) samplemax *= smpoct; else samplemax = samplemax / 2 + 1; if(samplemax == 0) samplemax = 1; //prepare a BIG FFT FFTwrapper *fft = new FFTwrapper(samplesize); fft_t *fftfreqs = new fft_t[samplesize / 2]; //this is used to compute frequency relation to the base frequency float adj[samplemax]; for(int nsample = 0; nsample < samplemax; ++nsample) adj[nsample] = (Pquality.oct + 1.0f) * (float)nsample / samplemax; for(int nsample = 0; nsample < samplemax; ++nsample) { if(do_abort()) goto exit; const float basefreqadjust = powf(2.0f, adj[nsample] - adj[samplemax - 1] * 0.5f); if(Pmode == 0) generatespectrum_bandwidthMode(spectrum, spectrumsize, basefreq * basefreqadjust, profile, profilesize, bwadjust); else generatespectrum_otherModes(spectrum, spectrumsize, basefreq * basefreqadjust); //the last samples contains the first samples //(used for linear/cubic interpolation) const int extra_samples = 5; PADnoteParameters::Sample newsample; newsample.smp = new float[samplesize + extra_samples]; newsample.smp[0] = 0.0f; for(int i = 1; i < spectrumsize; ++i) //randomize the phases fftfreqs[i] = FFTpolar(spectrum[i], (float)RND * 2 * PI); //that's all; here is the only ifft for the whole sample; //no windows are used ;-) fft->freqs2smps(fftfreqs, newsample.smp); //normalize(rms) float rms = 0.0f; for(int i = 0; i < samplesize; ++i) rms += newsample.smp[i] * newsample.smp[i]; rms = sqrt(rms); if(rms < 0.000001f) rms = 1.0f; rms *= sqrt(262144.0f / samplesize);//262144=2^18 for(int i = 0; i < samplesize; ++i) newsample.smp[i] *= 1.0f / rms * 50.0f; //prepare extra samples used by the linear or cubic interpolation for(int i = 0; i < extra_samples; ++i) newsample.smp[i + samplesize] = newsample.smp[i]; //yield new sample newsample.size = samplesize; newsample.basefreq = basefreq * basefreqadjust; cb(nsample, newsample); } exit: //Cleanup delete (fft); delete[] fftfreqs; delete[] spectrum; }
// Applies the parameters (i.e. computes all the samples, based on parameters); void PADnoteParameters::applyparameters(bool islocked) { const int samplesize = (((int)1) << (Pquality.samplesize + 14)); int spectrumsize = samplesize / 2; float spectrum[spectrumsize]; int profilesize = 512; float profile[profilesize]; float bwadjust = getprofile(profile, profilesize); // for (int i=0;i<profilesize;i++) profile[i]*=profile[i]; float basefreq = 65.406f * powf(2.0f, Pquality.basenote / 2); if (Pquality.basenote %2 == 1) basefreq *= 1.5; int samplemax = Pquality.oct + 1; int smpoct = Pquality.smpoct; if (Pquality.smpoct == 5) smpoct = 6; if (Pquality.smpoct == 6) smpoct = 12; if (smpoct != 0) samplemax *= smpoct; else samplemax = samplemax / 2 + 1; if (samplemax == 0) samplemax = 1; // prepare a BIG FFT stuff FFTwrapper *fft = new FFTwrapper(samplesize); FFTFREQS fftfreqs; FFTwrapper::newFFTFREQS(&fftfreqs, samplesize / 2); float adj[samplemax]; // this is used to compute frequency relation to the base frequency for (int nsample = 0; nsample < samplemax; ++nsample) adj[nsample] = (Pquality.oct + 1.0f) * (float)nsample / samplemax; for (int nsample = 0; nsample < samplemax; ++nsample) { float tmp = adj[nsample] - adj[samplemax - 1] * 0.5f; float basefreqadjust = powf(2.0f, tmp); if (Pmode == 0) generatespectrum_bandwidthMode(spectrum, spectrumsize, basefreq * basefreqadjust, profile, profilesize, bwadjust); else generatespectrum_otherModes(spectrum, spectrumsize, basefreq * basefreqadjust, profile, profilesize, bwadjust); const int extra_samples = 5; // the last samples contains the first // samples (used for linear/cubic interpolation) newsample.smp = new float[samplesize + extra_samples]; newsample.smp[0] = 0.0; for (int i = 1; i < spectrumsize; ++i) { // randomize the phases float phase = synth->numRandom() * 6.29f; fftfreqs.c[i] = spectrum[i] * cosf(phase); fftfreqs.s[i] = spectrum[i] * sinf(phase); } fft->freqs2smps(&fftfreqs, newsample.smp); // that's all; here is the only ifft for the whole sample; no windows are used ;-) // normalize(rms) float rms = 0.0; for (int i = 0; i < samplesize; ++i) rms += newsample.smp[i] * newsample.smp[i]; rms = sqrtf(rms); if (rms < 0.000001) rms = 1.0; rms *= sqrtf(262144.0f / samplesize); for (int i = 0; i < samplesize; ++i) newsample.smp[i] *= 1.0f / rms * 50.0f; // prepare extra samples used by the linear or cubic interpolation for (int i = 0; i < extra_samples; ++i) newsample.smp[i + samplesize] = newsample.smp[i]; // replace the current sample with the new computed sample if (!islocked) synth->actionLock(lockmute); deletesample(nsample); sample[nsample].smp = newsample.smp; sample[nsample].size = samplesize; sample[nsample].basefreq = basefreq * basefreqadjust; if (!islocked) synth->actionLock(unlock); newsample.smp = NULL; } delete fft; FFTwrapper::deleteFFTFREQS(&fftfreqs); // delete the additional samples that might exists and are not useful if (!islocked) synth->actionLock(lockmute); for (int i = samplemax; i < PAD_MAX_SAMPLES; ++i) deletesample(i); if (!islocked) synth->actionLock(unlock); }