diff --git a/CUETools.DSP.Mixer/AudioReadEventArgs.cs b/CUETools.DSP.Mixer/AudioReadEventArgs.cs
new file mode 100644
index 0000000..361daa8
--- /dev/null
+++ b/CUETools.DSP.Mixer/AudioReadEventArgs.cs
@@ -0,0 +1,11 @@
+using System;
+using CUETools.Codecs;
+
+namespace CUETools.DSP.Mixer
+{
+ public class AudioReadEventArgs : EventArgs
+ {
+ public IAudioSource source;
+ public AudioBuffer buffer;
+ }
+}
diff --git a/CUETools.DSP.Mixer/CUETools.DSP.Mixer.csproj b/CUETools.DSP.Mixer/CUETools.DSP.Mixer.csproj
index 4d90b7d..1cf42a6 100644
--- a/CUETools.DSP.Mixer/CUETools.DSP.Mixer.csproj
+++ b/CUETools.DSP.Mixer/CUETools.DSP.Mixer.csproj
@@ -57,7 +57,10 @@
-
+
+
+
+
diff --git a/CUETools.DSP.Mixer/Mixer.cs b/CUETools.DSP.Mixer/Mixer.cs
deleted file mode 100644
index af54f93..0000000
--- a/CUETools.DSP.Mixer/Mixer.cs
+++ /dev/null
@@ -1,378 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Text;
-using System.Threading;
-using System.Diagnostics;
-using CUETools.Codecs;
-
-namespace CUETools.DSP.Mixer
-{
- public class MixingSource : IAudioSource
- {
- AudioPCMConfig pcm;
- MixingBuffer[] buf;
- bool[] playing;
- float[] volume;
- long samplePos;
- int size;
- AudioReadEventArgs audioReadArgs = new AudioReadEventArgs();
-
- public event EventHandler AudioRead;
-
- public MixingSource(AudioPCMConfig pcm, int delay, int sources)
- {
- if (pcm.BitsPerSample != 32)
- throw new NotSupportedException("please use 32 bits per sample (float)");
- this.pcm = pcm;
- this.size = delay * pcm.SampleRate / 1000;
- this.buf = new MixingBuffer[2];
- this.buf[0] = new MixingBuffer(pcm, size, sources);
- this.buf[1] = new MixingBuffer(pcm, size, sources);
- this.playing = new bool[sources];
- this.volume = new float[sources];
- this.samplePos = 0;
- }
-
- public void Close()
- {
- }
-
- public long Position
- {
- get
- {
- return samplePos;
- }
- set
- {
- throw new NotSupportedException();
- }
- }
-
- public long Length
- {
- get
- {
- throw new NotSupportedException();
- }
- }
-
- public long Remaining
- {
- get
- {
- throw new NotSupportedException();
- }
- }
-
- public AudioPCMConfig PCM
- {
- get
- {
- return pcm;
- }
- }
-
- MixingBuffer mixbuff = null;
- int mixoffs = 0;
-
- public int Read(AudioBuffer result, int maxLength)
- {
- if (maxLength > (BufferSize - mixoffs) || maxLength < 0)
- maxLength = (BufferSize - mixoffs);
-
- result.Prepare(maxLength);
-
- if (mixbuff == null)
- mixbuff = LockFilledBuffer();
-
- float sumVolume = 0.0f;
- for (int iSource = 0; iSource < mixbuff.source.Length; iSource++)
- if (mixbuff.filled[iSource])
- sumVolume += mixbuff.volume[iSource];
- for (int iSource = 0; iSource < mixbuff.source.Length; iSource++)
- volume[iSource] = mixbuff.filled[iSource] ? mixbuff.volume[iSource] / Math.Max(1.0f, sumVolume) : 0.0f;
- for (int iSmp = 0; iSmp < result.Length; iSmp++)
- {
- for (int iChan = 0; iChan < result.PCM.ChannelCount; iChan++)
- {
- float sample = 0.0f;
- for (int iSource = 0; iSource < mixbuff.source.Length; iSource++)
- sample += mixbuff.source[iSource].Float[mixoffs + iSmp, iChan] * volume[iSource];
- result.Float[iSmp, iChan] = sample;
- }
- }
- mixoffs += result.Length;
- if (mixoffs == BufferSize)
- {
- UnlockFilledBuffer(mixbuff);
- mixbuff = null;
- mixoffs = 0;
- }
- samplePos += result.Length;
-
- if (AudioRead != null)
- {
- audioReadArgs.source = this;
- audioReadArgs.buffer = result;
- AudioRead(this, audioReadArgs);
- }
-
- return result.Length;
- }
-
- public string Path { get { return ""; } }
-
- public int BufferSize
- {
- get
- {
- return buf[0].source[0].Size;
- }
- }
-
- private bool IsFilled(MixingBuffer buf)
- {
- bool res = true;
- for (int i = 0; i < buf.filled.Length; i++)
- res &= buf.filled[i] || !this.playing[i];
- return res;
- }
-
- int current = 0;
-
- internal MixingBuffer LockFilledBuffer()
- {
- lock (this)
- {
- //Trace.WriteLine(string.Format("LockFilledBuffer: 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1]));
- int no = current;
- while (!IsFilled(buf[no]))
- Monitor.Wait(this);
- current = 1 - no;
- return buf[no];
- }
- }
-
- internal void UnlockFilledBuffer(MixingBuffer mixbuff)
- {
- lock (this)
- {
- //Trace.WriteLine(string.Format("UnockFilledBuffer: 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1]));
- for (int i = 0; i < mixbuff.filled.Length; i++)
- mixbuff.filled[i] = false;
- Monitor.PulseAll(this);
- }
- }
-
- public void BufferPlaying(int iSource, bool playing)
- {
- lock (this)
- {
- //Trace.WriteLine(string.Format("BufferPlaying{8}< 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
-
- this.playing[iSource] = playing;
- //if (!playing) buf0.filled[iSource] = false;
- //if (!playing) buf1.filled[iSource] = false;
-
- //Trace.WriteLine(string.Format("BufferPlaying{8}> 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
- Monitor.PulseAll(this);
- }
- }
-
- internal MixingBuffer LockEmptyBuffer(int iSource)
- {
- lock (this)
- {
- //Trace.WriteLine(string.Format("LockEmptyBuffer{8}: 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
-
- while (!playing[iSource] || buf[current].filled[iSource])
- Monitor.Wait(this);
-
- return buf[current];
- }
- }
-
- internal void UnlockEmptyBuffer(MixingBuffer mixbuff, int iSource, float volume)
- {
- lock (this)
- {
- //Trace.WriteLine(string.Format("UnlockEmptyBuffer{8}< 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
-
- mixbuff.volume[iSource] = volume;
- mixbuff.filled[iSource] = true;
-
- //Trace.WriteLine(string.Format("UnlockEmptyBuffer{8}> 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
- // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
-
- Monitor.PulseAll(this);
- }
- }
- }
-
- public class MixingBuffer
- {
- public AudioBuffer[] source;
- public float[] volume;
- public bool[] filled;
-
- public MixingBuffer(AudioPCMConfig pcm, int size, int sources)
- {
- source = new AudioBuffer[sources];
- volume = new float[sources];
- filled = new bool[sources];
- for (int i = 0; i < sources; i++)
- source[i] = new AudioBuffer(pcm, size);
- }
- }
-
- public class MixingWriter : IAudioDest
- {
- private MixingSource mixer;
- private int iSource;
- private long samplePos;
- private MixingBuffer mixbuff;
- private float volume;
-
- public MixingWriter(MixingSource mixer, int iSource)
- {
- this.mixer = mixer;
- this.iSource = iSource;
- this.samplePos = 0;
- this.mixbuff = null;
- this.volume = 1.0f;
- }
-
- public void Close()
- {
- }
-
- public void Delete()
- {
- Close();
- }
-
- public long Position
- {
- get { return samplePos; }
- set { throw new NotSupportedException(); }
- }
-
- public long FinalSampleCount
- {
- set { throw new NotSupportedException(); }
- }
-
- public long BlockSize
- {
- set { throw new NotSupportedException(); }
- }
-
- public int CompressionLevel
- {
- get { return 0; }
- set { throw new NotSupportedException(); }
- }
-
- public object Settings
- {
- get
- {
- return null;
- }
- set
- {
- if (value != null && value.GetType() != typeof(object))
- throw new Exception("Unsupported options " + value);
- }
- }
-
- public long Padding
- {
- set { }
- }
-
- public AudioPCMConfig PCM
- {
- get { return mixer.PCM; }
- }
-
- public float Volume
- {
- get
- {
- return volume;
- }
- set
- {
- volume = value;
- }
- }
-
- public void Pause()
- {
- mixer.LockEmptyBuffer(iSource);
- }
-
- public void Flush()
- {
- if (mixbuff != null)
- {
- if (mixbuff.source[iSource].Length < mixbuff.source[iSource].Size)
- AudioSamples.MemSet(mixbuff.source[iSource].Bytes, 0, mixbuff.source[iSource].Length * PCM.BlockAlign, (mixbuff.source[iSource].Size - mixbuff.source[iSource].Length) * PCM.BlockAlign);
- mixer.UnlockEmptyBuffer(mixbuff, iSource, volume);
- mixbuff = null;
- }
- }
-
- public void Write(AudioBuffer buff)
- {
- int bs = PCM.BlockAlign;
- int buff_offs = 0;
-
- while (buff_offs < buff.Length)
- {
- if (mixbuff == null)
- {
- mixbuff = mixer.LockEmptyBuffer(iSource);
- mixbuff.source[iSource].Prepare(-1);
- mixbuff.source[iSource].Length = 0;
- }
-
- int chunk = Math.Min(buff.Length - buff_offs, mixbuff.source[iSource].Size - mixbuff.source[iSource].Length);
- Buffer.BlockCopy(buff.Float, buff_offs * bs, mixbuff.source[iSource].Float, mixbuff.source[iSource].Length * bs, chunk * bs);
- mixbuff.source[iSource].Length += chunk;
- buff_offs += chunk;
-
- if (mixbuff.source[iSource].Length == mixbuff.source[iSource].Size)
- {
- mixer.UnlockEmptyBuffer(mixbuff, iSource, volume);
- mixbuff = null;
- }
- }
-
- samplePos += buff.Length;
- }
-
- public string Path { get { return ""; } }
- }
-
- public class AudioReadEventArgs: EventArgs
- {
- public IAudioSource source;
- public AudioBuffer buffer;
- }
-}
diff --git a/CUETools.DSP.Mixer/MixingBuffer.cs b/CUETools.DSP.Mixer/MixingBuffer.cs
new file mode 100644
index 0000000..3f8f41d
--- /dev/null
+++ b/CUETools.DSP.Mixer/MixingBuffer.cs
@@ -0,0 +1,22 @@
+using CUETools.Codecs;
+
+namespace CUETools.DSP.Mixer
+{
+ public class MixingBuffer
+ {
+ public AudioBuffer[] source;
+ public float[] volume;
+ public bool[] filled;
+
+ public MixingBuffer(AudioPCMConfig pcm, int size, int sources)
+ {
+ source = new AudioBuffer[sources];
+ volume = new float[sources];
+ filled = new bool[sources];
+ for (int i = 0; i < sources; i++)
+ {
+ source[i] = new AudioBuffer(pcm, size);
+ }
+ }
+ }
+}
diff --git a/CUETools.DSP.Mixer/MixingSource.cs b/CUETools.DSP.Mixer/MixingSource.cs
new file mode 100644
index 0000000..5812758
--- /dev/null
+++ b/CUETools.DSP.Mixer/MixingSource.cs
@@ -0,0 +1,205 @@
+using System;
+using System.Threading;
+using CUETools.Codecs;
+
+namespace CUETools.DSP.Mixer
+{
+ public class MixingSource : IAudioSource
+ {
+ private AudioPCMConfig pcm;
+ private MixingBuffer[] buf;
+ private bool[] playing;
+ private float[] volume;
+ private long samplePos;
+ private int size;
+ private AudioReadEventArgs audioReadArgs = new AudioReadEventArgs();
+ private MixingBuffer mixbuff = null;
+ private int mixoffs = 0;
+ private int current = 0;
+
+ public void Close()
+ {
+ }
+
+ public long Position
+ {
+ get { return samplePos; }
+ set { throw new NotSupportedException(); }
+ }
+
+ public long Length
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public long Remaining
+ {
+ get { throw new NotSupportedException(); }
+ }
+
+ public AudioPCMConfig PCM
+ {
+ get { return pcm; }
+ }
+
+ public string Path { get { return ""; } }
+
+ public int BufferSize
+ {
+ get
+ {
+ return buf[0].source[0].Size;
+ }
+ }
+
+ public MixingSource(AudioPCMConfig pcm, int delay, int sources)
+ {
+ if (pcm.BitsPerSample != 32)
+ throw new NotSupportedException("please use 32 bits per sample (float)");
+ this.pcm = pcm;
+ this.size = delay * pcm.SampleRate / 1000;
+ this.buf = new MixingBuffer[2];
+ this.buf[0] = new MixingBuffer(pcm, size, sources);
+ this.buf[1] = new MixingBuffer(pcm, size, sources);
+ this.playing = new bool[sources];
+ this.volume = new float[sources];
+ this.samplePos = 0;
+ }
+
+ public int Read(AudioBuffer result, int maxLength)
+ {
+ if (maxLength > (BufferSize - mixoffs) || maxLength < 0)
+ maxLength = (BufferSize - mixoffs);
+
+ result.Prepare(maxLength);
+
+ if (mixbuff == null)
+ mixbuff = LockFilledBuffer();
+
+ float sumVolume = 0.0f;
+ for (int iSource = 0; iSource < mixbuff.source.Length; iSource++)
+ if (mixbuff.filled[iSource])
+ sumVolume += mixbuff.volume[iSource];
+ for (int iSource = 0; iSource < mixbuff.source.Length; iSource++)
+ volume[iSource] = mixbuff.filled[iSource] ? mixbuff.volume[iSource] / Math.Max(1.0f, sumVolume) : 0.0f;
+ for (int iSmp = 0; iSmp < result.Length; iSmp++)
+ {
+ for (int iChan = 0; iChan < result.PCM.ChannelCount; iChan++)
+ {
+ float sample = 0.0f;
+ for (int iSource = 0; iSource < mixbuff.source.Length; iSource++)
+ sample += mixbuff.source[iSource].Float[mixoffs + iSmp, iChan] * volume[iSource];
+ result.Float[iSmp, iChan] = sample;
+ }
+ }
+ mixoffs += result.Length;
+ if (mixoffs == BufferSize)
+ {
+ UnlockFilledBuffer(mixbuff);
+ mixbuff = null;
+ mixoffs = 0;
+ }
+ samplePos += result.Length;
+
+ if (AudioRead != null)
+ {
+ audioReadArgs.source = this;
+ audioReadArgs.buffer = result;
+ AudioRead(this, audioReadArgs);
+ }
+
+ return result.Length;
+ }
+
+ private bool IsFilled(MixingBuffer buf)
+ {
+ bool res = true;
+ for (int i = 0; i < buf.filled.Length; i++)
+ res &= buf.filled[i] || !this.playing[i];
+ return res;
+ }
+
+ internal MixingBuffer LockFilledBuffer()
+ {
+ lock (this)
+ {
+ //Trace.WriteLine(string.Format("LockFilledBuffer: 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1]));
+ int no = current;
+ while (!IsFilled(buf[no]))
+ Monitor.Wait(this);
+ current = 1 - no;
+ return buf[no];
+ }
+ }
+
+ internal void UnlockFilledBuffer(MixingBuffer mixbuff)
+ {
+ lock (this)
+ {
+ //Trace.WriteLine(string.Format("UnockFilledBuffer: 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1]));
+ for (int i = 0; i < mixbuff.filled.Length; i++)
+ mixbuff.filled[i] = false;
+ Monitor.PulseAll(this);
+ }
+ }
+
+ public void BufferPlaying(int iSource, bool playing)
+ {
+ lock (this)
+ {
+ //Trace.WriteLine(string.Format("BufferPlaying{8}< 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
+
+ this.playing[iSource] = playing;
+ //if (!playing) buf0.filled[iSource] = false;
+ //if (!playing) buf1.filled[iSource] = false;
+
+ //Trace.WriteLine(string.Format("BufferPlaying{8}> 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
+ Monitor.PulseAll(this);
+ }
+ }
+
+ internal MixingBuffer LockEmptyBuffer(int iSource)
+ {
+ lock (this)
+ {
+ //Trace.WriteLine(string.Format("LockEmptyBuffer{8}: 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
+
+ while (!playing[iSource] || buf[current].filled[iSource])
+ Monitor.Wait(this);
+
+ return buf[current];
+ }
+ }
+
+ internal void UnlockEmptyBuffer(MixingBuffer mixbuff, int iSource, float volume)
+ {
+ lock (this)
+ {
+ //Trace.WriteLine(string.Format("UnlockEmptyBuffer{8}< 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
+
+ mixbuff.volume[iSource] = volume;
+ mixbuff.filled[iSource] = true;
+
+ //Trace.WriteLine(string.Format("UnlockEmptyBuffer{8}> 0.0: {0} {1}; 0.1: {2} {3}; 1.0: {4} {5}; 1.1: {6} {7};",
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1],
+ // buf0.playing[0], buf0.filled[0], buf0.playing[1], buf0.filled[1], iSource));
+
+ Monitor.PulseAll(this);
+ }
+ }
+
+ public event EventHandler AudioRead;
+ }
+}
diff --git a/CUETools.DSP.Mixer/MixingWriter.cs b/CUETools.DSP.Mixer/MixingWriter.cs
new file mode 100644
index 0000000..5a352cc
--- /dev/null
+++ b/CUETools.DSP.Mixer/MixingWriter.cs
@@ -0,0 +1,130 @@
+using System;
+using CUETools.Codecs;
+
+namespace CUETools.DSP.Mixer
+{
+ public class MixingWriter : IAudioDest
+ {
+ private MixingSource mixer;
+ private int iSource;
+ private long samplePos;
+ private MixingBuffer mixbuff;
+ private float volume;
+
+ public long Position
+ {
+ get { return samplePos; }
+ set { throw new NotSupportedException(); }
+ }
+
+ public long FinalSampleCount
+ {
+ set { throw new NotSupportedException(); }
+ }
+
+ public long BlockSize
+ {
+ set { throw new NotSupportedException(); }
+ }
+
+ public int CompressionLevel
+ {
+ get { return 0; }
+ set { throw new NotSupportedException(); }
+ }
+
+ public object Settings
+ {
+ get
+ {
+ return null;
+ }
+ set
+ {
+ if (value != null && value.GetType() != typeof(object))
+ throw new Exception("Unsupported options " + value);
+ }
+ }
+
+ public long Padding
+ {
+ set { }
+ }
+
+ public AudioPCMConfig PCM
+ {
+ get { return mixer.PCM; }
+ }
+
+ public float Volume
+ {
+ get { return volume; }
+ set { volume = value; }
+ }
+
+ public string Path { get { return ""; } }
+
+ public MixingWriter(MixingSource mixer, int iSource)
+ {
+ this.mixer = mixer;
+ this.iSource = iSource;
+ this.samplePos = 0;
+ this.mixbuff = null;
+ this.volume = 1.0f;
+ }
+
+ public void Close()
+ {
+ }
+
+ public void Delete()
+ {
+ Close();
+ }
+
+ public void Pause()
+ {
+ mixer.LockEmptyBuffer(iSource);
+ }
+
+ public void Flush()
+ {
+ if (mixbuff != null)
+ {
+ if (mixbuff.source[iSource].Length < mixbuff.source[iSource].Size)
+ AudioSamples.MemSet(mixbuff.source[iSource].Bytes, 0, mixbuff.source[iSource].Length * PCM.BlockAlign, (mixbuff.source[iSource].Size - mixbuff.source[iSource].Length) * PCM.BlockAlign);
+ mixer.UnlockEmptyBuffer(mixbuff, iSource, volume);
+ mixbuff = null;
+ }
+ }
+
+ public void Write(AudioBuffer buff)
+ {
+ int bs = PCM.BlockAlign;
+ int buff_offs = 0;
+
+ while (buff_offs < buff.Length)
+ {
+ if (mixbuff == null)
+ {
+ mixbuff = mixer.LockEmptyBuffer(iSource);
+ mixbuff.source[iSource].Prepare(-1);
+ mixbuff.source[iSource].Length = 0;
+ }
+
+ int chunk = Math.Min(buff.Length - buff_offs, mixbuff.source[iSource].Size - mixbuff.source[iSource].Length);
+ Buffer.BlockCopy(buff.Float, buff_offs * bs, mixbuff.source[iSource].Float, mixbuff.source[iSource].Length * bs, chunk * bs);
+ mixbuff.source[iSource].Length += chunk;
+ buff_offs += chunk;
+
+ if (mixbuff.source[iSource].Length == mixbuff.source[iSource].Size)
+ {
+ mixer.UnlockEmptyBuffer(mixbuff, iSource, volume);
+ mixbuff = null;
+ }
+ }
+
+ samplePos += buff.Length;
+ }
+ }
+}