Пример #1
0
        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();
            }
        }
Пример #2
0
        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);
        }
Пример #3
0
        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
        }
Пример #4
0
        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;
        }
Пример #5
0
 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();
     }
 }
Пример #6
0
        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
        }
Пример #7
0
        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
        }
Пример #8
0
        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));
        }
Пример #9
0
 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;
     }
 }
Пример #10
0
        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();
            }
        }
Пример #11
0
        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();
            }
        }
Пример #12
0
        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
        }
Пример #13
0
        /* 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);
        }
Пример #14
0
        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);
        }