//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// devTimeStretcher //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void DevSuite::devTimeStretcher() { Logger msg( "devTimeStretcher" ); msg << Msg::Info << "Running devTimeStretcher..." << Msg::EndReq; // std::unique_ptr< std::vector< Music::Note > > trueMelody( new std::vector< Music::Note >() ); // RawPcmData::Ptr data = TestDataSupply::generateRandomMelody( trueMelody.get() ); // RawPcmData::Ptr data = TestDataSupply::getCurrentTestSample(); SamplingInfo samplingInfo; Synthesizer::SineGenerator sineGen( samplingInfo ); sineGen.setFrequency( 440 ); RawPcmData::Ptr data = sineGen.generate( 1024 * 128 + 46 ); Music::TimeStretcher timeStretchAlg( 2 ); RawPcmData stretchedMusic = timeStretchAlg.execute( *data ); gPlotFactory().createPlot( "RegeneratedWaveFile" ); gPlotFactory().drawPcmData( *data ); gPlotFactory().drawPcmData( stretchedMusic, Qt::red ); data->normaliseToPeak(); stretchedMusic.normaliseToPeak(); MultiChannelRawPcmData waveData( new RawPcmData( *data ) ); MultiChannelRawPcmData waveDataStretched( new RawPcmData( stretchedMusic ) ); // WaveFile::write( "OriginalBeforeStretch.wav", waveData ); // WaveFile::write( "StretchedMusic.wav", waveDataStretched ); }
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// /// devImprovedPeakAlgorithm //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// void DevSuite::devImprovedPeakAlgorithm() { Logger msg( "devImprovedPeakAlgorithm" ); msg << Msg::Info << "Running devImprovedPeakAlgorithm..." << Msg::EndReq; // Take fourier bin size = 4096 // Take sine with phase = 0 // Make center frequency variable // Pick range around center frequency with delta_freq // Compute max rel amp as function of freq delta (envelope) // First sort by amp, remove all non-increasing frequency entries size_t fourierSize = 4096; size_t zeroPadSize = 3*fourierSize; const RealVector& centreFreqs = realVector( 400 ); double deltaRange = 100; size_t numFreqs = 100; const double freqDelta = deltaRange / numFreqs; SamplingInfo samplingInfo; Synthesizer::SineGenerator sineGen( samplingInfo ); RealVector relMaxY; RealVector diffX; for ( size_t iCentreFreq = 0; iCentreFreq < centreFreqs.size(); ++iCentreFreq ) { for ( size_t iFreq = 0; iFreq < numFreqs; ++iFreq ) { double frequency = centreFreqs[ iCentreFreq ] + freqDelta * iFreq; sineGen.setFrequency( frequency ); RawPcmData::Ptr data = sineGen.generate( fourierSize ); WaveAnalysis::SpectralReassignmentTransform transform( samplingInfo, fourierSize, zeroPadSize, 2 ); WaveAnalysis::StftData::Ptr stftData = transform.execute( *data ); const WaveAnalysis::SrSpectrum& spec = stftData->getSrSpectrum( 0 ); const RealVector& x = spec.getFrequencies(); RealVector&& y = spec.getMagnitude(); y /= Utils::getMaxValue( y ); RealVector deltaX = x - frequency; // msg << Msg::Info << deltaX << Msg::EndReq; relMaxY.insert( relMaxY.end(), y.begin(), y.end() ); diffX.insert( diffX.end(), deltaX.begin(), deltaX.end() ); } } SortCache relYSc( diffX ); const RealVector& relMaxYSorted = relYSc.applyTo( relMaxY ); const RealVector& relDiffXSorted = relYSc.applyTo( diffX ); Math::Log10Function log10; gPlotFactory().createPlot( "envelope" ); gPlotFactory().createGraph( relDiffXSorted, relMaxYSorted ); // Create envelope by requiring linear interpolation is always above curve. size_t nEnvelopeSamples = 500; RealVector linearGrid = Utils::createRangeReal( -1000, 1000, nEnvelopeSamples ); RealVector zeros = RealVector( nEnvelopeSamples, 0 ); gPlotFactory().createScatter( linearGrid, zeros, Plotting::MarkerDrawAttr( Qt::red ) ); gPlotFactory().createPlot( "envelopLog" ); gPlotFactory().createGraph( relDiffXSorted, log10.evalMany( relMaxYSorted ) ); // RealVector fCorr = spec.getFrequencyCorrections(); // for ( size_t i = 0; i < spec.getFrequencies().size(); ++i ) // { // fCorr[ i ] /= spec.getFrequency( i ); // } // Math::Log10Function log10Fct; // gPlotFactory().createPlot( "plot1" ); // gPlotFactory().createGraph( x, log10Fct.evalMany( y ), Qt::blue ); // gPlotFactory().createScatter( x, log10Fct.evalMany( y ) ); // gPlotFactory().createGraph( x, log10Fct.evalMany( fCorr ), Qt::green ); // gPlotFactory().createScatter( x, log10Fct.evalMany( fCorr ), Plotting::MarkerDrawAttr( Qt::red ) ); // msg << Msg::Info << "Number of spectra in STFT: " << stftData->getNumSpectra() << Msg::EndReq; // for ( size_t iSpec = 0; iSpec < stftData->getNumSpectra(); ++iSpec ) // { // const WaveAnalysis::WindowLocation* windowLoc = stftData->getSpectrum( iSpec ).getWindowLocation(); // msg << Msg::Info << "WindowLocation: [" << windowLoc->getFirstSample() << ", " << windowLoc->getLastSample() << "]" << Msg::EndReq; // } }
void YSE::DSP::sineWave::process(SOUND_STATUS & intent, Int & latency) { Flt lastVolume = volumeCurve.getBack(); Clamp(lastVolume, 0.f, 1.f); if (latency >= STANDARD_BUFFERSIZE) { // no new attack, but a previous curve might not be done yet if (intent == SS_STOPPED || intent == SS_PAUSED) { // complete fade out if needed if (lastVolume > 0) { volumeCurve.drawLine(0, (UInt)(lastVolume * 200), lastVolume, 0); volumeCurve.drawLine((UInt)((lastVolume)* 200), STANDARD_BUFFERSIZE, 0); } else { volumeCurve = 0.f; } } else if (intent == SS_PLAYING) { // complete fade in if needed if (lastVolume < 1) { volumeCurve.drawLine(0, (UInt)((1 - lastVolume) * 200), lastVolume, 1); volumeCurve.drawLine((UInt)((1 - lastVolume) * 200), STANDARD_BUFFERSIZE, 1); } else { volumeCurve = 1.f; } } else { // in all other cases continue the previous volume status volumeCurve = lastVolume; } // frequency can be changed within a note, but if intent != playing, we assume // it will change on the next attack if (intent != SS_PLAYING) { // just keep the last freqency frequencyCurve = currentFrequency; } else { currentFrequency = parmFrequency; frequencyCurve = currentFrequency; } } else if (latency == 0) { // no latency at all, just do everything at the beginning of the sample if (intent == SS_STOPPED || intent == SS_PAUSED) { // complete fade out if needed if (lastVolume > 0) { volumeCurve.drawLine(0, (UInt)(lastVolume * 200), lastVolume, 0); volumeCurve.drawLine((UInt)((lastVolume)* 200), STANDARD_BUFFERSIZE, 0); } else { volumeCurve = 0.f; } frequencyCurve = currentFrequency; } else if (intent == SS_PLAYING) { // complete fade in if needed if (lastVolume < 1) { volumeCurve.drawLine(0, (UInt)((1 - lastVolume) * 200), lastVolume, 1); volumeCurve.drawLine((UInt)((1 - lastVolume) * 200), STANDARD_BUFFERSIZE, 1); } else { volumeCurve = 1.f; } frequencyCurve = currentFrequency; } else if (intent == SS_WANTSTOPLAY || intent == SS_WANTSTORESTART) { volumeCurve.drawLine(0, 200, lastVolume, 1); volumeCurve.drawLine(200, STANDARD_BUFFERSIZE, 1); currentFrequency = parmFrequency; frequencyCurve = currentFrequency; intent = SS_PLAYING; } else if (intent == SS_WANTSTOPAUSE || intent == SS_WANTSTOSTOP) { volumeCurve.drawLine(0, 200, lastVolume, 0); volumeCurve.drawLine(200, STANDARD_BUFFERSIZE, 0); frequencyCurve = currentFrequency; intent = SS_STOPPED; } } else { // latency > 0, but smaller as buffersize // this means the change has to come somewhere in the middle of the sample // no new attack, but a previous curve might not be done yet if (intent == SS_STOPPED || intent == SS_PAUSED) { // complete fade out if needed if (lastVolume > 0) { volumeCurve.drawLine(0, (UInt)(lastVolume * 200), lastVolume, 0); volumeCurve.drawLine((UInt)((lastVolume)* 200), STANDARD_BUFFERSIZE, 0); } else { volumeCurve = 0.f; } frequencyCurve = currentFrequency; } else if (intent == SS_PLAYING) { // complete fade in if needed if (lastVolume < 1) { volumeCurve.drawLine(0, (UInt)((1 - lastVolume) * 200), lastVolume, 1); volumeCurve.drawLine((UInt)((1 - lastVolume) * 200), STANDARD_BUFFERSIZE, 1); } else { volumeCurve = 1.f; } frequencyCurve = currentFrequency; } else if (intent == SS_WANTSTOPLAY || intent == SS_WANTSTORESTART) { Int slopeLength = (latency + 200) >= STANDARD_BUFFERSIZE ? STANDARD_BUFFERSIZE - latency : 200; volumeCurve.drawLine(0, latency, lastVolume); volumeCurve.drawLine(latency, latency + slopeLength, lastVolume, slopeLength * 0.005f); if ((latency + slopeLength) < STANDARD_BUFFERSIZE) { volumeCurve.drawLine(latency + slopeLength, STANDARD_BUFFERSIZE, 1); } // change frequency after latency frequencyCurve.drawLine(0, latency, currentFrequency); currentFrequency = parmFrequency; frequencyCurve.drawLine(latency, STANDARD_BUFFERSIZE, currentFrequency); intent = SS_PLAYING; } else if (intent == SS_WANTSTOSTOP || intent == SS_WANTSTOPAUSE) { Int slopeLength = latency + 200 > STANDARD_BUFFERSIZE ? STANDARD_BUFFERSIZE - latency : 200; volumeCurve.drawLine(0, latency, lastVolume); volumeCurve.drawLine(latency, latency + slopeLength, lastVolume, 1 - slopeLength * 0.005f); if (latency + slopeLength < STANDARD_BUFFERSIZE) { volumeCurve.drawLine(latency + slopeLength, STANDARD_BUFFERSIZE, 0); } // we don't care about frequency here because it's inaudible anyway frequencyCurve = currentFrequency; intent = SS_STOPPED; } } YSE::DSP::buffer & sin = sineGen(frequencyCurve); for (UInt i = 0; i < buffer.size(); i++) { buffer[i] = sin; buffer[i] *= volumeCurve; } latency -= STANDARD_BUFFERSIZE; if (latency < 0) latency = 0; }