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 } }
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); }
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; }
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); }