Example #1
0
        public void ForcePlay(Sound sound)
        {
            var newState = new SynthState(sound);

            if (Interlocked.Exchange(ref m_state, newState) != null)
            {
                Interlocked.Increment(ref m_soundsCompleted);
                m_soundQueueEnd = m_soundQueueStart; // Clear queue
            }
        }
Example #2
0
        public bool PlayIfIdle(Sound sound)
        {
            var newState = new SynthState(sound);

            if (Interlocked.CompareExchange(ref m_state, newState, null) == null)
            {
                m_soundQueueEnd = m_soundQueueStart; // Clear queue
                return(true);
            }
            return(false);
        }
Example #3
0
        public SpeakerChannel()
        {
            m_state           = null;
            m_soundsCompleted = 0;

            m_soundQueue      = new Sound[SOUND_QUEUE_SIZE];
            m_soundQueueStart = 0;
            m_soundQueueEnd   = 0;

            m_noiseBuffer = new short[NOISE_BUFFER_SIZE];
            FillNoiseBuffer(m_noiseBuffer);
            m_phase    = 0.0f;
            m_vibPhase = 0.0f;
        }
Example #4
0
        public int Synth(short[] buffer, int start, int samples, int channels, int sampleRate, int channel)
        {
            var state = m_state;

            if (state == null)
            {
                return(0);
            }

            var   sound        = state.Sound;
            float frequency    = ClampFrequency(state.Frequency);
            float slide        = sound.Slide;
            float attack       = sound.Attack;
            float duration     = sound.Duration;
            float decay        = sound.Decay;
            float amplitude    = sound.Volume * MASTER_VOLUME;
            float vibFrequency = sound.VibratoFrequency;
            float vibDepth     = sound.VibratoDepth;
            float duty         = sound.Duty;

            float sampleRatef = (float)sampleRate;
            int   firstSample = state.SamplesPlayed;

            int end = (int)(duration * (float)sampleRate);
            int outputSamples;

            if (firstSample + samples > end)
            {
                outputSamples = end - firstSample;
            }
            else
            {
                outputSamples = samples;
            }

            // Fill the buffer with the base waveform
            float phase             = m_phase;
            float vibPhase          = m_vibPhase;
            float vibPhaseIncrement = vibFrequency / sampleRatef;

            switch (sound.Waveform)
            {
            case Waveform.Square:
            default:
            {
                for (int i = 0; i < outputSamples; ++i)
                {
                    buffer[start + i * channels + channel] = SampleSquare(phase, duty);
                    frequency += (slide / sampleRatef);
                    vibPhase   = (vibPhase + vibPhaseIncrement) % 1.0f;
                    float vibbedFrequency = ClampFrequency(frequency + vibDepth * SampleSin(vibPhase));
                    phase = (phase + (vibbedFrequency / sampleRatef)) % 1.0f;
                }
                break;
            }

            case Waveform.Triangle:
            {
                for (int i = 0; i < outputSamples; ++i)
                {
                    buffer[start + i * channels + channel] = SampleTriangle(phase);
                    frequency += (slide / sampleRatef);
                    vibPhase   = (vibPhase + vibPhaseIncrement) % 1.0f;
                    float vibbedFrequency = ClampFrequency(frequency + vibDepth * SampleSin(vibPhase));
                    phase = (phase + (vibbedFrequency / sampleRatef)) % 1.0f;
                }
                break;
            }

            case Waveform.Sawtooth:
            {
                for (int i = 0; i < outputSamples; ++i)
                {
                    buffer[start + i * channels + channel] = SampleSawtooth(phase);
                    frequency += (slide / sampleRatef);
                    vibPhase   = (vibPhase + vibPhaseIncrement) % 1.0f;
                    float vibbedFrequency = ClampFrequency(frequency + vibDepth * SampleSin(vibPhase));
                    phase = (phase + (vibbedFrequency / sampleRatef)) % 1.0f;
                }
                break;
            }

            case Waveform.Noise:
            {
                var noiseBuffer = m_noiseBuffer;
                for (int i = 0; i < outputSamples; ++i)
                {
                    buffer[start + i * channels + channel] = SampleNoise(phase, noiseBuffer);
                    frequency += (slide / sampleRatef);
                    vibPhase   = (vibPhase + vibPhaseIncrement) % 1.0f;
                    float vibbedFrequency = ClampFrequency(frequency + vibDepth * SampleSin(vibPhase));
                    phase = phase + (vibbedFrequency / sampleRatef);
                    if (phase >= 1.0f)
                    {
                        FillNoiseBuffer(noiseBuffer);
                        phase %= 1.0f;
                    }
                }
                break;
            }
            }

            // Shape the buffer to the envelope
            float t          = (float)firstSample / sampleRatef;
            float tIncrement = 1.0f / (float)sampleRate;

            for (int i = 0; i < outputSamples; ++i)
            {
                var idx = start + i * channels + channel;
                buffer[idx] = (short)((float)buffer[idx] * amplitude);
                if (t < attack)
                {
                    var f = t / attack;
                    buffer[idx] = (short)((float)buffer[idx] * f);
                }
                if (t > (duration - decay))
                {
                    var f = 1.0f - ((t - (duration - decay)) / decay);
                    buffer[idx] = (short)((float)buffer[idx] * f);
                }
                t += tIncrement;
            }

            // Store state
            state.SamplesPlayed += outputSamples;
            state.Frequency      = frequency;
            m_phase              = phase;
            m_vibPhase           = vibPhase;

            if (outputSamples < samples)
            {
                if (m_soundQueueEnd > m_soundQueueStart)
                {
                    // Play the next sound
                    var newState = new SynthState(m_soundQueue[m_soundQueueStart % SOUND_QUEUE_SIZE]);
                    if (Interlocked.CompareExchange(ref m_state, newState, state) == state)
                    {
                        Interlocked.Increment(ref m_soundsCompleted);
                        Interlocked.Increment(ref m_soundQueueStart);

                        // Play some of the new sound
                        int unwrittenSamples = samples - outputSamples;
                        if (unwrittenSamples > 0)
                        {
                            return(outputSamples + Synth(buffer, start + outputSamples * channels, unwrittenSamples, channels, sampleRate, channel));
                        }
                    }
                }
                else if (sound.Loop)
                {
                    // Loop the sound
                    state.SamplesPlayed = 0;
                    int unwrittenSamples = samples - outputSamples;
                    if (unwrittenSamples > 0)
                    {
                        return(outputSamples + Synth(buffer, start + outputSamples * channels, unwrittenSamples, channels, sampleRate, channel));
                    }
                }
                else
                {
                    // Finish the sound
                    if (Interlocked.CompareExchange(ref m_state, null, state) == state)
                    {
                        Interlocked.Increment(ref m_soundsCompleted);
                    }
                    m_phase    = 0.0f;
                    m_vibPhase = 0.0f;
                }
            }

            return(outputSamples);
        }