Browse Source

some enhancements for MP3 playback

pull/1/head
markheath 17 years ago
parent
commit
dda24a637f
  1. 3
      NAudio/Changes.xml
  2. 58
      NAudio/Wave/Compression/AcmStream.cs
  3. 10
      NAudio/Wave/Compression/AcmStreamHeader.cs
  4. 5
      NAudio/Wave/WaveOutputs/WasapiOut.cs
  5. 19
      NAudio/Wave/WaveStreams/WaveChannel32.cs
  6. 16
      NAudioDemo/AudioPlaybackForm.cs

3
NAudio/Changes.xml

@ -831,9 +831,12 @@
<change>
<version>1.2.135.0</version>
<author>Mark Heath</author>
<date>13 Jun 2008</date>
<desc>More unit tests for AudioClient</desc>
<desc>Added option for WASAPI exclusive mode to NAudio Demo (not working yet)</desc>
<desc>NAudioDemo can play MP3 files (not at low latency though)</desc>
<desc>Position bar in NAudioDemo</desc>
<desc>Performance enhancements to WaveChannel32</desc>
<desc>MP3 playback less choppy</desc>
</change>
</changes>

58
NAudio/Wave/Compression/AcmStream.cs

@ -13,6 +13,7 @@ namespace NAudio.Wave
private IntPtr streamHandle;
private IntPtr driverHandle;
private AcmStreamHeader streamHeader;
private WaveFormat sourceFormat;
/// <summary>
/// Creates a new ACM stream to convert one format to another. Note that
@ -22,16 +23,35 @@ namespace NAudio.Wave
/// <param name="destFormat">The destination audio format</param>
public AcmStream(WaveFormat sourceFormat, WaveFormat destFormat)
{
int sourceBufferSize = sourceFormat.AverageBytesPerSecond;
sourceBufferSize -= (sourceBufferSize % sourceFormat.BlockAlign);
MmException.Try(AcmInterop.acmStreamOpen(out streamHandle, IntPtr.Zero, sourceFormat, destFormat, null, 0, 0, AcmStreamOpenFlags.NonRealTime), "acmStreamOpen");
streamHeader = new AcmStreamHeader(streamHandle, sourceBufferSize, SourceToDest(sourceBufferSize));
driverHandle = IntPtr.Zero;
try
{
streamHandle = IntPtr.Zero;
this.sourceFormat = sourceFormat;
int sourceBufferSize = Math.Max(16384, sourceFormat.AverageBytesPerSecond);
sourceBufferSize -= (sourceBufferSize % sourceFormat.BlockAlign);
MmException.Try(AcmInterop.acmStreamOpen(out streamHandle, IntPtr.Zero, sourceFormat, destFormat, null, 0, 0, AcmStreamOpenFlags.NonRealTime), "acmStreamOpen");
streamHeader = new AcmStreamHeader(streamHandle, sourceBufferSize, SourceToDest(sourceBufferSize));
driverHandle = IntPtr.Zero;
}
catch
{
// suppress the finalise and clean up resources
Dispose();
throw;
}
}
/// <summary>
/// Creates a new ACM stream to convert one format to another, using a
/// specified driver identified and wave filter
/// </summary>
/// <param name="driverId">the driver identifier</param>
/// <param name="sourceFormat">the source format</param>
/// <param name="waveFilter">the wave filter</param>
public AcmStream(int driverId, WaveFormat sourceFormat, WaveFilter waveFilter)
{
int sourceBufferSize = sourceFormat.AverageBytesPerSecond;
int sourceBufferSize = Math.Max(16384, sourceFormat.AverageBytesPerSecond);
this.sourceFormat = sourceFormat;
sourceBufferSize -= (sourceBufferSize % sourceFormat.BlockAlign);
MmException.Try(AcmInterop.acmDriverOpen(out driverHandle, driverId, 0), "acmDriverOpen");
MmException.Try(AcmInterop.acmStreamOpen(out streamHandle, driverHandle,
@ -104,6 +124,24 @@ namespace NAudio.Wave
}
}
/// <summary>
/// Converts the contents of the SourceBuffer into the DestinationBuffer
/// </summary>
/// <param name="bytesToConvert">The number of bytes in the SourceBuffer
/// that need to be converted</param>
/// <param name="sourceBytesConverted">The number of source bytes actually converted</param>
/// <returns>The number of converted bytes in the DestinationBuffer</returns>
public int Convert(int bytesToConvert, out int sourceBytesConverted)
{
if (bytesToConvert % sourceFormat.BlockAlign != 0)
{
System.Diagnostics.Debug.WriteLine(String.Format("NOT A WHOLE NUMBER OF BLOCKS", bytesToConvert));
bytesToConvert -= (bytesToConvert % sourceFormat.BlockAlign);
}
return streamHeader.Convert(bytesToConvert, out sourceBytesConverted);
}
/// <summary>
/// Converts the contents of the SourceBuffer into the DestinationBuffer
/// </summary>
@ -112,7 +150,13 @@ namespace NAudio.Wave
/// <returns>The number of converted bytes in the DestinationBuffer</returns>
public int Convert(int bytesToConvert)
{
return streamHeader.Convert(bytesToConvert);
int sourceBytesConverted;
int destBytes = Convert(bytesToConvert, out sourceBytesConverted);
if (sourceBytesConverted != bytesToConvert)
{
throw new MmException(MmResult.NotSupported, "AcmStreamHeader.Convert didn't convert everything");
}
return destBytes;
}
/* Relevant only for async conversion streams

10
NAudio/Wave/Compression/AcmStreamHeader.cs

@ -52,7 +52,7 @@ namespace NAudio.Wave
}
}
public int Convert(int bytesToConvert)
public int Convert(int bytesToConvert, out int sourceBytesConverted)
{
Prepare();
try
@ -63,13 +63,7 @@ namespace NAudio.Wave
MmException.Try(AcmInterop.acmStreamConvert(streamHandle, streamHeader, flags), "acmStreamConvert");
firstTime = false;
System.Diagnostics.Debug.Assert(streamHeader.destBufferLength == destBuffer.Length, "Codecs should not change dest buffer length");
if (streamHeader.sourceBufferLengthUsed != bytesToConvert)
{
// TODO: a more appropriate exception type
throw new MmException(MmResult.NotSupported, "AcmStreamHeader.Convert didn't convert everything");
}
int bytesConverted = streamHeader.destBufferLengthUsed;
sourceBytesConverted = streamHeader.sourceBufferLengthUsed;
}
finally
{

5
NAudio/Wave/WaveOutputs/WasapiOut.cs

@ -35,10 +35,15 @@ namespace NAudio.Wave
public WasapiOut(AudioClientShareMode shareMode, int latency) :
this(GetDefaultAudioEndpoint(), shareMode, latency)
{
}
static MMDevice GetDefaultAudioEndpoint()
{
if (Environment.OSVersion.Version.Major < 6)
{
throw new NotSupportedException("WASAPI supported only on Windows Vista and above");
}
MMDeviceEnumerator enumerator = new MMDeviceEnumerator();
return enumerator.GetDefaultAudioEndpoint(DataFlow.Render,Role.Console);
}

19
NAudio/Wave/WaveStreams/WaveChannel32.cs

@ -102,6 +102,20 @@ namespace NAudio.Wave
}
}
byte[] sourceBuffer;
/// <summary>
/// Helper function to avoid creating a new buffer every read
/// </summary>
byte[] GetSourceBuffer(int bytesRequired)
{
if (sourceBuffer == null || sourceBuffer.Length < bytesRequired)
{
sourceBuffer = new byte[Math.Min(sourceStream.WaveFormat.AverageBytesPerSecond,bytesRequired)];
}
return sourceBuffer;
}
/// <summary>
/// Reads bytes from this wave stream
/// </summary>
@ -124,7 +138,7 @@ namespace NAudio.Wave
if (sourceStream.WaveFormat.Channels == 1)
{
int sourceBytesRequired = (numBytes - bytesWritten) / 4;
byte[] sourceBuffer = new byte[sourceBytesRequired];
byte[] sourceBuffer = GetSourceBuffer(sourceBytesRequired);
int read = sourceStream.Read(sourceBuffer, 0, sourceBytesRequired);
MonoToStereo(destBuffer, offset + bytesWritten, sourceBuffer, read);
bytesWritten += (read * 4);
@ -132,7 +146,7 @@ namespace NAudio.Wave
else
{
int sourceBytesRequired = (numBytes - bytesWritten) / 2;
byte[] sourceBuffer = new byte[sourceBytesRequired];
byte[] sourceBuffer = GetSourceBuffer(sourceBytesRequired);
int read = sourceStream.Read(sourceBuffer, 0, sourceBytesRequired);
AdjustVolume(destBuffer, offset + bytesWritten, sourceBuffer, read);
bytesWritten += (read * 2);
@ -156,6 +170,7 @@ namespace NAudio.Wave
float* pfDestBuffer = (float*)pDestBuffer;
short* psSourceBuffer = (short*)pSourceBuffer;
// TODO:implement better panning laws. This one has 50% volume in middle
float leftVolume = (volume * (1 - pan) / 2.0f) / 32768f;
float rightVolume = (volume * (pan + 1) / 2.0f) / 32768f;
int samplesRead = bytesRead / 2;

16
NAudioDemo/AudioPlaybackForm.cs

@ -49,7 +49,15 @@ namespace NAudioDemo
return;
}
CreateWaveOut();
try
{
CreateWaveOut();
}
catch (Exception driverCreateException)
{
MessageBox.Show(String.Format("{0}", driverCreateException.Message));
return;
}
WaveStream reader = CreateInputStream(fileName);
trackBarPosition.Maximum = (int) reader.TotalTime.TotalSeconds;
@ -62,10 +70,10 @@ namespace NAudioDemo
return;
}
WaveMixerStream32 mixer = new WaveMixerStream32(inputs, false);
//WaveMixerStream32 mixer = new WaveMixerStream32(inputs, false);
//Wave32To16Stream mixdown = new Wave32To16Stream(mixer);
mainOutputStream = mixer;
waveOut.Init(mixer);
mainOutputStream = inputs[0];
waveOut.Init(mainOutputStream);
waveOut.Volume = volumeSlider1.Volume;
groupBoxDriverModel.Enabled = false;
waveOut.Play();

Loading…
Cancel
Save