private static void ThreadMain(object obj) { OutputGeneric <T, U, W> state = (OutputGeneric <T, U, W>)obj; try { using (state.destinationHandler = state.createDestinationHandler( state.destination, state.channels, state.bits, state.samplingRate, state.destinationHandlerParams)) { state.generatorMainLoop( state.generatorParams, DataCallback, state, state.stopper); state.destinationHandler.Finish(state.stopper.Stopped); } } catch (Exception exception) { // generator method should record and defer exceptions. this one got through string message = (exception is ApplicationException) ? exception.Message : exception.ToString(); Program.WriteLog("OutputGeneric.ThreadMain", message); MessageBox.Show(message, "Synthesis Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); } finally { state.waitFinishedHelper.NotifyFinished(); } }
public static OutputGeneric<T, WaveTableTestGeneratorParams<T, W>, W> Do( string baseName, GetDestinationMethod<T> getDestination, CreateDestinationHandlerMethod<T, W> createDestinationHandler, W destinationHandlerArguments, GeneratorMainLoopMethod<T, WaveTableTestGeneratorParams<T, W>, W> generatorMainLoop, WaveTableTestGeneratorParams<T, W> generatorParams, GeneratorCompletionMethod<WaveTableTestGeneratorParams<T, W>> generatorCompletion, IMainWindowServices mainWindow, NumChannelsType channels, NumBitsType bits, int samplingRate, int oversamplingFactor, bool showProgressWindow, bool modal) { // prerequisites return OutputGeneric<T, WaveTableTestGeneratorParams<T, W>, W>.Do( baseName, getDestination, createDestinationHandler, destinationHandlerArguments, generatorMainLoop, generatorParams, generatorCompletion, channels, bits, samplingRate, oversamplingFactor, showProgressWindow, modal); }
private void buttonTest_MouseDown(object sender, MouseEventArgs e) { const double BufferDuration = .25f; IPlayPrefsProvider playPrefsProvider = mainWindow.GetPlayPrefsProvider(); #if true // prevents "Add New Data Source..." from working state = WaveTableTestGeneratorParams<OutputDeviceDestination, OutputDeviceArguments>.Do( mainWindow.DisplayName, OutputDeviceEnumerator.OutputDeviceGetDestination, OutputDeviceEnumerator.CreateOutputDeviceDestinationHandler, new OutputDeviceArguments(BufferDuration), WaveTableTestGeneratorParams<OutputDeviceDestination, OutputDeviceArguments>.MainLoop, generatorParams = new WaveTableTestGeneratorParams<OutputDeviceDestination, OutputDeviceArguments>( waveTableObject.WaveTableData, waveTableObject.TestAttackDuration, waveTableObject.TestDecayDuration, waveTableObject.NumBits, playPrefsProvider.SamplingRate, waveTableObject.TestFrequency), WaveTableTestGeneratorParams<OutputDeviceDestination, OutputDeviceArguments>.Completion, mainWindow, NumChannelsType.eSampleMono, waveTableObject.NumBits, playPrefsProvider.SamplingRate, 1/*oversampling*/, false/*showProgressWindow*/, false/*modal*/); #endif }
private void buttonTest_MouseUp(object sender, MouseEventArgs e) { state.stopper.Stop(); if (generatorParams.exception != null) { MessageBox.Show(generatorParams.exception.ToString()); } state.Dispose(); state = null; generatorParams = null; }
public static void MainLoop <U>( AudioFilePlayGeneratorParams <T, W> generatorParams, Synthesizer.DataOutCallbackMethod <OutputGeneric <T, U, W> > dataCallback, OutputGeneric <T, U, W> dataCallbackState, Synthesizer.StopTask stopper) { try { const int NUMPOINTS = 256; float[] buffer = new float[NUMPOINTS]; float[] buffer2 = new float[NUMPOINTS * 2]; int c; while ((c = generatorParams.reader.ReadPoints(buffer, 0, buffer.Length)) != 0) { if (stopper.Stopped) { break; } if (generatorParams.reader.NumChannels == NumChannelsType.eSampleStereo) { dataCallback( dataCallbackState, buffer, 0, c / 2); } else { for (int i = 0; i < c; i++) { buffer2[2 * i + 0] = buffer[i]; buffer2[2 * i + 1] = buffer[i]; } dataCallback( dataCallbackState, buffer2, 0, c); } } } catch (Exception exception) { generatorParams.exception = exception; stopper.Stop(); } }
private void buttonStop_Click(object sender, EventArgs e) { if (state != null) { state.stopper.Stop(); state = null; } #if false if (generatorParams.exception != null) { MessageBox.Show(generatorParams.exception.ToString()); } state = null; generatorParams = null; #endif }
public void Play(string path, IMainWindowServices mainWindow) { Stream stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, Constants.BufferSize); AudioFileReader reader = null; try { reader = new WAVReader(stream); } catch (FormatException) { try { stream.Seek(0, SeekOrigin.Begin); reader = new AIFFReader(stream); } catch (FormatException) { MessageBox.Show("File is not a recognized AIFF or WAV file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } const double BufferDuration = 2; #if true // prevents "Add New Data Source..." from working state = AudioFilePlayGeneratorParams <OutputDeviceDestination, OutputDeviceArguments> .Do( mainWindow.DisplayName, OutputDeviceEnumerator.OutputDeviceGetDestination, OutputDeviceEnumerator.CreateOutputDeviceDestinationHandler, new OutputDeviceArguments(BufferDuration), AudioFilePlayGeneratorParams <OutputDeviceDestination, OutputDeviceArguments> .MainLoop, generatorParams = new AudioFilePlayGeneratorParams <OutputDeviceDestination, OutputDeviceArguments>( reader), AudioFilePlayGeneratorParams <OutputDeviceDestination, OutputDeviceArguments> .Completion, mainWindow, reader.NumChannels, reader.NumBits, reader.SamplingRate, 1 /*oversampling*/, true /*showProgressWindow*/, true /*modal*/); #endif }
public static OutputGeneric <T, SynthesizerGeneratorParams <T, W>, W> Do( string baseName, GetDestinationMethod <T> getDestination, CreateDestinationHandlerMethod <T, W> createDestinationHandler, W destinationHandlerArguments, GeneratorMainLoopMethod <T, SynthesizerGeneratorParams <T, W>, W> generatorMainLoop, SynthesizerGeneratorParams <T, W> generatorParams, GeneratorCompletionMethod <SynthesizerGeneratorParams <T, W> > generatorCompletion, IMainWindowServices mainWindow, NumChannelsType channels, NumBitsType bits, int samplingRate, int oversamplingFactor, bool showProgressWindow, bool modal) { // prerequisites /* force an auto-save since play may take a long time */ MainWindow.DoAutosaveGlobally(); /* make sure all objects are up to date */ if (!mainWindow.MakeUpToDate()) { /* couldn't compile score elements */ return(null); } return(OutputGeneric <T, SynthesizerGeneratorParams <T, W>, W> .Do( baseName, getDestination, createDestinationHandler, destinationHandlerArguments, generatorMainLoop, generatorParams, generatorCompletion, channels, bits, samplingRate, oversamplingFactor, showProgressWindow, modal)); }
public static void SynthesizerMainLoop <U>( SynthesizerGeneratorParams <T, W> generatorParams, Synthesizer.DataOutCallbackMethod <OutputGeneric <T, U, W> > dataCallback, OutputGeneric <T, U, W> dataCallbackState, Synthesizer.StopTask stopper) { try { generatorParams.result = Synthesizer.DoSynthesizer( generatorParams.document, dataCallback, dataCallbackState, generatorParams.listOfTracks, generatorParams.keyTrack, generatorParams.frameToStartAt, generatorParams.samplingRate * generatorParams.oversamplingFactor, generatorParams.oversamplingFactor, generatorParams.envelopeRate, generatorParams.defaultBeatsPerMinute, generatorParams.overallVolumeScalingReciprocal, generatorParams.scanningGap, stopper, generatorParams.showSummary, out generatorParams.errorInfo, generatorParams.interactionLog, generatorParams.deterministic, generatorParams.randomSeed, generatorParams.automationSettings); } catch (Exception exception) { Program.WriteLog("SynthesizerMainLoop", exception.ToString()); generatorParams.exception = exception; stopper.Stop(); } finally { generatorParams.completed = true; } }
public static void MainLoop<U>( WaveTableTestGeneratorParams<T, W> generatorParams, Synthesizer.DataOutCallbackMethod<OutputGeneric<T, U, W>> dataCallback, OutputGeneric<T, U, W> dataCallbackState, Synthesizer.StopTask stopper) { try { // Unoptimized - since only one runs at a time this codepath is not perf critical (unlike the // resampler loops in the synth engine) int NumTables = generatorParams.data.NumTables; float[][] ReferenceArray = new float[NumTables][]; for (int i = 0; i < NumTables; i++) { ReferenceArray[i] = generatorParams.data.ListOfTables[i].frames; } int PlaybackSamplingRate = generatorParams.samplingRate; if (PlaybackSamplingRate < Constants.MINSAMPLINGRATE) { PlaybackSamplingRate = Constants.MINSAMPLINGRATE; } if (PlaybackSamplingRate > Constants.MAXSAMPLINGRATE) { PlaybackSamplingRate = Constants.MAXSAMPLINGRATE; } int FramesPerTable = generatorParams.data.NumFrames; /* this is the initial index into the wave table */ Synthesizer.Fixed64 WaveformIndex = new Synthesizer.Fixed64(); /* this is the 16.16 bit fixed point number used to increment the index */ /* into the wave table */ Synthesizer.Fixed64 WaveformIncrementor = new Synthesizer.Fixed64( FramesPerTable * generatorParams.frequency / PlaybackSamplingRate); /* the number of times each wave slice has to be used */ int NumberOfIterationsAttack = (int)(generatorParams.attack * PlaybackSamplingRate); int NumberOfIterationsDecay = (int)(generatorParams.decay * PlaybackSamplingRate); const int SOUNDBUFFERLENGTHFRAMES = 256; float[] OutputBuffer = new float[SOUNDBUFFERLENGTHFRAMES * 2]; int OutputIndex = 0; for (int i = 0; i < NumberOfIterationsAttack + NumberOfIterationsDecay; i++) { /* compute wave table index for attack/decay phase */ double TableIndex; if (i < NumberOfIterationsAttack) { TableIndex = (double)i / NumberOfIterationsAttack; } else { TableIndex = (double)(NumberOfIterationsDecay + NumberOfIterationsAttack - i) / NumberOfIterationsDecay; } float Value = Synthesizer.WaveTableIndexer( WaveformIndex.Double, TableIndex * (NumTables - 1), NumTables, FramesPerTable, ReferenceArray, true/*EnableCrossWaveTableInterpolation*/); WaveformIndex += WaveformIncrementor; OutputBuffer[2 * OutputIndex + 0] = OutputBuffer[2 * OutputIndex + 1] = Value * .5f; OutputIndex++; if (OutputIndex == SOUNDBUFFERLENGTHFRAMES) { dataCallback( dataCallbackState, OutputBuffer, 0, SOUNDBUFFERLENGTHFRAMES); OutputIndex = 0; if (stopper.Stopped) { return; } } } dataCallback( dataCallbackState, OutputBuffer, 0, OutputIndex); } catch (Exception exception) { generatorParams.exception = exception; stopper.Stop(); } }
public static void MainLoop <U>( PlayFileWithEffectsGeneratorParams <T, W> generatorParams, Synthesizer.DataOutCallbackMethod <OutputGeneric <T, U, W> > dataCallback, OutputGeneric <T, U, W> dataCallbackState, Synthesizer.StopTask stopper) { try { generatorParams.result = Synthesizer.SynthStateRec.InitializeSynthesizer( out generatorParams.synthState, generatorParams.mainWindow.Document, new List <TrackObjectRec>(), null, 0 /*FrameToStartAt*/, generatorParams.reader.SamplingRate, 1 /*Oversampling*/, generatorParams.mainWindow.Document.EnvelopeUpdateRate, (LargeBCDType)generatorParams.mainWindow.Document.DefaultBeatsPerMinute, 1 /*OverallVolumeScalingReciprocal*/, (LargeBCDType)0d /*ScanningGap*/, out generatorParams.errorInfo, TextWriter.Synchronized(generatorParams.interactionLog), generatorParams.mainWindow.Document.Deterministic, generatorParams.mainWindow.Document.Seed, new Synthesizer.AutomationSettings()); if (generatorParams.result != Synthesizer.SynthErrorCodes.eSynthDone) { return; } // HACK! generatorParams.result = Synthesizer.NewTrackEffectGenerator( generatorParams.effectSpec, generatorParams.synthState.SynthParams0, out generatorParams.synthState.ScoreEffectProcessor); if (generatorParams.result != Synthesizer.SynthErrorCodes.eSynthDone) { return; } while (!stopper.Stopped) { // TODO: shouldn't ask for nAllocatedPointsOneChannel, that's slightly inaccurate. Should // use the clock logic in SynthGenerateOneCycle -- see e.g. nActualFrames int c; if (generatorParams.reader.NumChannels == NumChannelsType.eSampleMono) { c = generatorParams.reader.ReadPoints( generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.ScoreWorkspaceLOffset, generatorParams.synthState.SynthParams0.nAllocatedPointsOneChannel); Synthesizer.FloatVectorCopy( generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.ScoreWorkspaceLOffset, generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.ScoreWorkspaceROffset, c); } else { c = generatorParams.reader.ReadPoints( generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.SectionWorkspaceLOffset, generatorParams.synthState.SynthParams0.nAllocatedPointsOneChannel * 2); c /= 2; Synthesizer.FloatVectorMakeUninterleaved( generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.SectionWorkspaceLOffset, generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.ScoreWorkspaceLOffset, generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.ScoreWorkspaceROffset, c); } if (c == 0) { break; } // HACK! // Should create specialized version of Synthesizer.SynthGenerateOneCycle that does this Synthesizer.UpdateStateTrackEffectGenerator( generatorParams.synthState.ScoreEffectProcessor, generatorParams.synthState.SynthParams0); Synthesizer.ApplyTrackEffectGenerator( generatorParams.synthState.ScoreEffectProcessor, generatorParams.synthState.SynthParams0.workspace, c, generatorParams.synthState.SynthParams0.ScoreWorkspaceLOffset, generatorParams.synthState.SynthParams0.ScoreWorkspaceROffset, generatorParams.synthState.SynthParams0); Synthesizer.FloatVectorMakeInterleaved( generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.ScoreWorkspaceLOffset, generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.ScoreWorkspaceROffset, c, generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.SectionWorkspaceLOffset); dataCallback( dataCallbackState, generatorParams.synthState.SynthParams0.workspace, generatorParams.synthState.SynthParams0.SectionWorkspaceLOffset, c); } } catch (Exception exception) { generatorParams.exception = exception; stopper.Stop(); } }
private void buttonPlay_Click(object sender, EventArgs e) { MainWindow.DoAutosaveGlobally(); if (!mainWindow.MakeUpToDate()) { return; } Synthesizer.EffectSpecListRec effectSpec; if (!BuildThis(out effectSpec)) { return; } const double BufferDuration = 2f; #if false if (state != null) { state.stopper.Stop(); } state = null; #endif Stream stream = new FileStream(textBoxAudioFilePath.Text, FileMode.Open, FileAccess.Read, FileShare.Read, Constants.BufferSize); AudioFileReader reader = null; try { reader = new WAVReader(stream); } catch (FormatException) { try { stream.Seek(0, SeekOrigin.Begin); reader = new AIFFReader(stream); } catch (FormatException) { MessageBox.Show("File is not a recognized AIFF or WAV file.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } } #if true // prevents "Add New Data Source..." from working #if false state = #endif PlayFileWithEffectsGeneratorParams <OutputDeviceDestination, OutputDeviceArguments> .Do( Path.GetFileNameWithoutExtension(textBoxAudioFilePath.Text), OutputDeviceEnumerator.OutputDeviceGetDestination, OutputDeviceEnumerator.CreateOutputDeviceDestinationHandler, new OutputDeviceArguments(BufferDuration), PlayFileWithEffectsGeneratorParams <OutputDeviceDestination, OutputDeviceArguments> .MainLoop, #if false generatorParams = #endif new PlayFileWithEffectsGeneratorParams <OutputDeviceDestination, OutputDeviceArguments>( stream, reader, effectSpec, mainWindow), PlayFileWithEffectsGeneratorParams <OutputDeviceDestination, OutputDeviceArguments> .Completion, mainWindow, reader.NumChannels, reader.NumBits, reader.SamplingRate, 1 /*oversampling*/, true /*showProgressWindow*/, true /*modal*/); #endif }
/* synthesizer calls back and passes data to this routine */ private static Synthesizer.SynthErrorCodes DataCallback( OutputGeneric <T, U, W> state, float[] data, int offset, int frameCount) { #if DEBUG if ((state.bits != NumBitsType.eSample8bit) && (state.bits != NumBitsType.eSample16bit) && (state.bits != NumBitsType.eSample24bit)) { Debug.Assert(false); throw new ArgumentException(); } #endif /* drop samples for oversampling */ if (state.oversamplingFactor > 1) { /* initialize read scan and write scan where we left off last time */ int writeScan = 0; int readScan = state.oversamplingSkipCarryover; /* scan over, dropping all but each OversamplingFactor sample */ while (readScan < frameCount) { /* copy value over */ data[2 * writeScan + 0 + offset] = data[2 * readScan + 0 + offset]; data[2 * writeScan + 1 + offset] = data[2 * readScan + 1 + offset]; /* step to next value */ writeScan += 1; readScan += state.oversamplingFactor; } /* update buffer size and save state */ state.oversamplingSkipCarryover = readScan - frameCount; frameCount = writeScan; } /* if output is mono, average the channels */ if (state.channels == NumChannelsType.eSampleMono) { for (int i = 0; i < frameCount; i++) { data[i + offset] = .5f * (data[2 * i + 0 + offset] + data[2 * i + 1 + offset]); } } /* compute number of samples */ int pointCount = frameCount; if (state.channels == NumChannelsType.eSampleStereo) { pointCount *= 2; } /* load state */ float localMaxClipExtent = state.maxClipExtent; int localClippedSampleCount = state.clippedSampleCount; /* apply dither */ if ((state.bits == NumBitsType.eSample8bit) || (state.bits == NumBitsType.eSample16bit)) { if (state.channels == NumChannelsType.eSampleStereo) { state.ditherState.DoStereo( frameCount, data, offset); } else { state.ditherState.DoMono( frameCount, data, offset); } } /* clip, round, and scale the data */ for (int i = 0; i < pointCount; i++) { float value = data[i + offset]; /* find absolute value, and save sign */ float sign = 1; if (value < 0) { value = -value; sign = -sign; } /* clip value at 1 */ if (value > 1) { localClippedSampleCount++; if (value > localMaxClipExtent) { localMaxClipExtent = value; } value = 1; } data[i + offset] = sign * value; } /* save state */ state.maxClipExtent = localMaxClipExtent; state.clippedSampleCount = localClippedSampleCount; state.destinationHandler.Post(data, offset, pointCount); state.totalSampleCount += frameCount; return(Synthesizer.SynthErrorCodes.eSynthDone); }
public static OutputGeneric <T, U, W> Do( string baseName, GetDestinationMethod <T> getDestination, CreateDestinationHandlerMethod <T, W> createDestinationHandler, W destinationHandlerParams, GeneratorMainLoopMethod <T, U, W> generatorMainLoop, U generatorParams, GeneratorCompletionMethod <U> generatorCompletion, NumChannelsType channels, NumBitsType bits, int samplingRate, int oversamplingFactor, bool showProgressWindow, bool modal) // modal is only meaningful when showProgressWindow==true { // set up processing record OutputGeneric <T, U, W> state = new OutputGeneric <T, U, W>(); state.channels = channels; state.bits = bits; state.samplingRate = samplingRate; state.oversamplingFactor = oversamplingFactor; state.totalSampleCount = 0; state.clippedSampleCount = 0; state.maxClipExtent = 0; state.oversamplingSkipCarryover = 0; if ((state.bits == NumBitsType.eSample8bit) || (state.bits == NumBitsType.eSample16bit)) { if (OutputGeneric <T, U, W> .UseHPTRI) // TODO: add dither selector to global settings { state.ditherState = new Synthesizer.StereoDither_HPTRI(bits); } else { state.ditherState = new Synthesizer.StereoDither_TPDF(bits); } } if (!getDestination(out state.destination)) { return(null); } state.createDestinationHandler = createDestinationHandler; state.generatorMainLoop = generatorMainLoop; state.generatorParams = generatorParams; state.generatorCompletion = generatorCompletion; state.destinationHandlerParams = destinationHandlerParams; state.stopper = new Synthesizer.StopTask(); state.waitFinishedHelper = new WaitFinishedHelper(); // All synth parameter initialization must be done by this point to avoid race conditions!!! state.thread = new Thread(ThreadMain); state.thread.Start(state); if (showProgressWindow) { state.progressWindow = new OutputProgressWindow( baseName, true /*show clipping*/, state, state, state.stopper, state.waitFinishedHelper, state.waitFinishedHelper, delegate() { ClipInfo clipInfo = new ClipInfo( state.totalSampleCount, state.clippedSampleCount, state.maxClipExtent); state.generatorCompletion( generatorParams, ref clipInfo); }); if (modal) { state.progressWindow.ShowDialog(); state.Dispose(); // suppress finalize } else { state.progressWindow.Show(); // client required to dispose after completion } } // After this, the dialog prevents UI interaction with the application on the main thread // and the rendering thread does it's thing until finished. // The dialog and the rendering thread talk to each other about stopping and completion. return(state); }