/// <summary> /// Pans a sound. /// This method was initially written using the guide at https://docs.microsoft.com/en-us/windows/win32/xaudio2/how-to--pan-a-sound /// The code has finally been improved thanks to the MonoGame framework code: https://github.com/MonoGame/MonoGame /// </summary> /// <param name="sound">The sound to pan.</param> /// <param name="pan">The value by which to pan the sound. -1.0f is completely left, and 1.0f is completely right. 0.0f is center.</param> public static void setPan(ExtendedAudioBuffer sound, float pan) { SpeakerConfiguration mask; if (mainSoundDevice.Version == XAudio2Version.Version27) { WaveFormatExtensible deviceFormat = mainSoundDevice.GetDeviceDetails(0).OutputFormat; mask = (SpeakerConfiguration)deviceFormat.ChannelMask; } else { mask = (SpeakerConfiguration)mainMasteringVoice.ChannelMask; } VoiceDetails soundDetails = sound.getVoiceDetails(); VoiceDetails masteringDetails = mainMasteringVoice.VoiceDetails; int srcChannelCount = soundDetails.InputChannelCount; int dstChannelCount = masteringDetails.InputChannelCount; // Create an array to hold the output matrix. Warning : the minimum size of the output matrix is the number of channels in the source voice times the number of channels in the output voice. // Note that the outputMatrix indices are placed in the same order as the SharpDX.Multimedia.Speakers enum. // Don't forget there are two times more cells in the matrix if the source sound is stereo) float[] outputMatrix = new float[srcChannelCount * dstChannelCount]; Array.Clear(outputMatrix, 0, outputMatrix.Length); // From there, we'll hope that the sound file is either mono or stereo. If the WAV had more than 2 channels, it would be to difficult to handle. // Similarly, we'll also only output to the front-left and front-right speakers for simplicity, e.g. like the XNA framework does. if (srcChannelCount == 1) // Mono source { // Left/Right output levels: // Pan -1.0: L = 1.0, R = 0.0 // Pan 0.0: L = 1.0, R = 1.0 // Pan +1.0: L = 0.0, R = 1.0 outputMatrix[0] = (pan > 0f) ? ((1f - pan)) : 1f; // Front-left output outputMatrix[1] = (pan < 0f) ? ((1f + pan)) : 1f; // Front-right output } else if (srcChannelCount == 2) // Stereo source { // Left/Right input (Li/Ri) mix for Left/Right outputs (Lo/Ro): // Pan -1.0: Lo = 0.5Li + 0.5Ri, Ro = 0.0Li + 0.0Ri // Pan 0.0: Lo = 1.0Li + 0.0Ri, Ro = 0.0Li + 1.0Ri // Pan +1.0: Lo = 0.0Li + 0.0Ri, Ro = 0.5Li + 0.5Ri if (pan <= 0f) { outputMatrix[0] = 1f + pan * 0.5f; // Front-left output, Left input outputMatrix[1] = -pan * 0.5f; // Front-left output, Right input outputMatrix[2] = 0f; // Front-right output, Left input outputMatrix[3] = 1f + pan; // Front-right output, Right input } else { outputMatrix[0] = 1f - pan; // Front-left output, Left input outputMatrix[1] = 0f; // Front-left output, Right input outputMatrix[2] = pan * 0.5f; // Front-right output, Left input outputMatrix[3] = 1f - pan * 0.5f; // Front-right output, Right input } } sound.setOutputMatrix(soundDetails.InputChannelCount, masteringDetails.InputChannelCount, outputMatrix); }
/// <summary> /// Pans a sound. /// This method was written using the guide at https://docs.microsoft.com/en-us/windows/win32/xaudio2/how-to--pan-a-sound /// </summary> /// <param name="sound">The sound to pan.</param> /// <param name="pan">The value by which to pan the sound. -1.0f is completely left, and 1.0f is completely right. 0.0f is center.</param> public static void setPan(ExtendedAudioBuffer sound, float pan) { SpeakerConfiguration mask = (SpeakerConfiguration)mainMasteringVoice.ChannelMask; float[] outputMatrix = new float[8]; float left = 0.5f - pan / 2; float right = 0.5f + pan / 2; switch (mask) { case SpeakerConfiguration.mono: outputMatrix[0] = 1.0f; break; case SpeakerConfiguration.stereo: case SpeakerConfiguration.twoPointOne: case SpeakerConfiguration.surround: outputMatrix[0] = left; outputMatrix[1] = right; break; case SpeakerConfiguration.quad: outputMatrix[0] = outputMatrix[2] = left; outputMatrix[1] = outputMatrix[3] = right; break; case SpeakerConfiguration.fourPointOne: outputMatrix[0] = outputMatrix[3] = left; outputMatrix[1] = outputMatrix[4] = right; break; case SpeakerConfiguration.fivePointOne: case SpeakerConfiguration.sevenPointOne: case SpeakerConfiguration.fivePointOneSurround: outputMatrix[0] = outputMatrix[4] = left; outputMatrix[1] = outputMatrix[5] = right; break; case SpeakerConfiguration.sevenPointOneSurround: outputMatrix[0] = outputMatrix[4] = outputMatrix[6] = left; outputMatrix[1] = outputMatrix[5] = outputMatrix[7] = right; break; } VoiceDetails soundDetails = sound.getVoiceDetails(); VoiceDetails masteringDetails = mainMasteringVoice.VoiceDetails; sound.setOutputMatrix(soundDetails.InputChannelCount, masteringDetails.InputChannelCount, outputMatrix); }