void UpdateSound() { // Try to keep 1/10 seconds of sound in the buffer, to avoid both dropouts and unnecessary latency float targetLength = 1.0f / 10.0f; float requiredLength = targetLength - soundStream.BufferLength; if (requiredLength < 0.0f) { return; } uint numSamples = (uint)(soundStream.Frequency * requiredLength); if (numSamples == 0) { return; } // Allocate a new buffer and fill it with a simple two-oscillator algorithm. The sound is over-amplified // (distorted), clamped to the 16-bit range, and finally lowpass-filtered according to the coefficient var newData = new short[numSamples]; for (int i = 0; i < numSamples; ++i) { osc1 = osc1 + 1.0f % 360.0f; osc2 = osc2 + 1.002f % 360.0f; float newValue = MathHelper.Clamp((float)((Math.Sin(osc1) + Math.Sin(osc2)) * 100000.0f), -32767.0f, 32767.0f); accumulator = MathHelper.Lerp(accumulator, newValue, filter); newData[i] = (short)accumulator; } // Queue buffer to the stream for playback soundStream.AddData(newData, 0, newData.Length); }
// https://github.com/microsoft/MixedRealityCompanionKit/blob/master/LegacySpectatorView/Samples/SharedHolograms/Assets/HoloToolkit/Utilities/Scripts/TextToSpeech.cs private async Task <BufferedSoundStream> SpeechStreamToSoundStream(SpeechSynthesisStream inStream) { var outStream = new BufferedSoundStream(); uint size = (uint)inStream.Size; byte[] wavAudio = new byte[size]; using (var inputStream = inStream.GetInputStreamAt(0)) { inStream.Dispose(); using (var reader = new DataReader(inputStream)) { await reader.LoadAsync(size); reader.ReadBytes(wavAudio); } } int channelCount = wavAudio[22]; int frequency = BytesToInt(wavAudio, 24); outStream.SetFormat((uint)frequency, true, channelCount == 2); // Get past all the other sub chunks to get to the data subchunk: int pos = 12; // First subchunk ID from 12 to 16 // Keep iterating until we find the data chunk (i.e. 64 61 74 61 ...... (i.e. 100 97 116 97 in decimal)) while (!(wavAudio[pos] == 100 && wavAudio[pos + 1] == 97 && wavAudio[pos + 2] == 116 && wavAudio[pos + 3] == 97)) { pos += 4; int chunkSize = wavAudio[pos] + wavAudio[pos + 1] * 256 + wavAudio[pos + 2] * 65536 + wavAudio[pos + 3] * 16777216; pos += 4 + chunkSize; } pos += 8; // Pos is now positioned to start of actual sound data. int sampleCount = (wavAudio.Length - pos) / 2; // 2 bytes per sample (16 bit sound mono) if (channelCount == 2) { sampleCount /= 2; } // 4 bytes per sample (16 bit stereo) outStream.AddData(wavAudio, pos); return(outStream); }