Unify CRecordDevice handling
This commit is contained in:
1 parent
bb2df2cc8e
commit
052e32aa6c
5 files changed
+18
-795
No files matched your search
@@ -15,13 +15,9 @@
|
||||
// along with Vocaluxe. If not, see <http://www.gnu.org/licenses/>.
|
||||
#endregion
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Gst;
|
||||
using GLib;
|
||||
using System.Runtime.InteropServices;
|
||||
using Vocaluxe.Base;
|
||||
using VocaluxeLib;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound.Playback.GstreamerSharp
|
||||
{
|
||||
@@ -209,285 +205,5 @@ namespace Vocaluxe.Lib.Sound.Playback.GstreamerSharp
|
||||
foreach (int key in streamsToDelete)
|
||||
_Streams.Remove(key);
|
||||
}
|
||||
|
||||
private class CGstreamerSharpAudioStream
|
||||
{
|
||||
private Element _Element;
|
||||
private bool _Loop;
|
||||
public volatile bool Closed = true;
|
||||
public volatile bool Finished;
|
||||
|
||||
private CFading _Fading;
|
||||
private EStreamAction _AfterFadeAction;
|
||||
private float _Volume = 1f;
|
||||
|
||||
private float _MaxVolume = 1f;
|
||||
|
||||
private volatile float _Duration = -1f;
|
||||
private volatile float _Position;
|
||||
private volatile bool _QueryingDuration;
|
||||
|
||||
public CGstreamerSharpAudioStream(string media, bool prescan)
|
||||
{
|
||||
Element convert = ElementFactory.Make("audioconvert", "convert");
|
||||
Element audiosink = ElementFactory.Make("directsoundsink", "audiosink");
|
||||
var audioSinkBin = new Bin("Audiosink");
|
||||
|
||||
if (convert == null || audiosink == null)
|
||||
{
|
||||
CLog.LogError("Could not create pipeline");
|
||||
return;
|
||||
}
|
||||
|
||||
audioSinkBin.Add(convert);
|
||||
audioSinkBin.Add(audiosink);
|
||||
convert.Link(audiosink);
|
||||
Pad pad = convert.GetStaticPad("sink");
|
||||
GhostPad ghostpad = new GhostPad("sink", pad);
|
||||
|
||||
if (pad == null)
|
||||
{
|
||||
CLog.LogError("Could not create pads");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ghostpad.SetActive(true))
|
||||
{
|
||||
CLog.LogError("Could not link pads");
|
||||
return;
|
||||
}
|
||||
if (!audioSinkBin.AddPad(ghostpad))
|
||||
{
|
||||
CLog.LogError("Could not add pad");
|
||||
return;
|
||||
}
|
||||
|
||||
_Element = ElementFactory.Make("playbin", "playbin");
|
||||
if (_Element == null)
|
||||
{
|
||||
CLog.LogError("Could not create playbin");
|
||||
return;
|
||||
}
|
||||
_Element["audio-sink"] = audioSinkBin;
|
||||
_Element["flags"] = 1 << 1;
|
||||
_Element["uri"] = new Uri(media).AbsoluteUri;
|
||||
_Element.SetState(State.Paused);
|
||||
|
||||
Closed = false; //Enable stream
|
||||
|
||||
// Passing CLOCK_TIME_NONE here causes the pipeline to block for a long time so with
|
||||
// prescan enabled the pipeline will wait 500ms for stream to initialize and then continue
|
||||
// if it takes more than 500ms, duration queries will be performed asynchronously
|
||||
if (prescan)
|
||||
{
|
||||
Message msg = _Element.Bus.TimedPopFiltered(0xffffffffffffffff, MessageType.AsyncDone);
|
||||
if (msg.Handle != IntPtr.Zero)
|
||||
_UpdateDuration();
|
||||
}
|
||||
}
|
||||
|
||||
private void _OnMessage(Message msg)
|
||||
{
|
||||
if (msg.Handle == IntPtr.Zero)
|
||||
return;
|
||||
switch (msg.Type)
|
||||
{
|
||||
case MessageType.Eos:
|
||||
if (_Loop)
|
||||
Position = 0;
|
||||
else
|
||||
{
|
||||
Finished = true;
|
||||
Close();
|
||||
}
|
||||
break;
|
||||
case MessageType.Error:
|
||||
GException error;
|
||||
string debug;
|
||||
msg.ParseError(out error, out debug);
|
||||
CLog.LogError("Gstreamer error: message" + error.Message + ", code" + error.Code + " ,debug information" + debug);
|
||||
break;
|
||||
case MessageType.DurationChanged:
|
||||
if (!_QueryingDuration)
|
||||
_UpdateDuration();
|
||||
break;
|
||||
}
|
||||
msg.Unref();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (!Closed)
|
||||
{
|
||||
Closed = true;
|
||||
Finished = true;
|
||||
var t = new System.Threading.Thread(_TerminateStream) {Name = "GSt Terminate"};
|
||||
t.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private void _TerminateStream()
|
||||
{
|
||||
if (_Element != null)
|
||||
{
|
||||
_Element.SetState(State.Null);
|
||||
_Element.Dispose();
|
||||
_Element = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Play(bool loop = false)
|
||||
{
|
||||
if (_Element != null)
|
||||
_Element.SetState(State.Playing);
|
||||
_Loop = loop;
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
if (_Element != null)
|
||||
_Element.SetState(State.Ready);
|
||||
Position = 0;
|
||||
}
|
||||
|
||||
public void Fade(float targetVolume, float seconds)
|
||||
{
|
||||
_Fading = new CFading(_Volume, targetVolume, seconds);
|
||||
_AfterFadeAction = EStreamAction.Nothing;
|
||||
}
|
||||
|
||||
public void FadeAndPause(float targetVolume, float seconds)
|
||||
{
|
||||
Fade(targetVolume, seconds);
|
||||
_AfterFadeAction = EStreamAction.Pause;
|
||||
}
|
||||
|
||||
public void FadeAndClose(float targetVolume, float seconds)
|
||||
{
|
||||
Fade(targetVolume, seconds);
|
||||
_AfterFadeAction = EStreamAction.Close;
|
||||
}
|
||||
|
||||
public void FadeAndStop(float targetVolume, float seconds)
|
||||
{
|
||||
Fade(targetVolume, seconds);
|
||||
_AfterFadeAction = EStreamAction.Stop;
|
||||
}
|
||||
|
||||
public float Volume
|
||||
{
|
||||
get { return _Volume * 100f; }
|
||||
set
|
||||
{
|
||||
_Volume = value / 100f;
|
||||
if (_Element != null)
|
||||
_Element["volume"] = (_Volume * _MaxVolume);
|
||||
}
|
||||
}
|
||||
|
||||
public float MaxVolume
|
||||
{
|
||||
get { return _MaxVolume * 100f; }
|
||||
set
|
||||
{
|
||||
_MaxVolume = value / 100f;
|
||||
Volume = _Volume;
|
||||
}
|
||||
}
|
||||
|
||||
public float Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_Duration < 0 && !_QueryingDuration)
|
||||
{
|
||||
_QueryingDuration = true; // Set this to avoid race conditions
|
||||
var t = new System.Threading.Thread(_UpdateDuration) {Name = "GSt Update Duration"};
|
||||
t.Start();
|
||||
}
|
||||
return _Duration > 0 ? _Duration : -1;
|
||||
}
|
||||
}
|
||||
|
||||
public float Position
|
||||
{
|
||||
get
|
||||
{
|
||||
long position;
|
||||
if (!_Element.QueryPosition(Format.Time, out position))
|
||||
CLog.LogError("Could not query position");
|
||||
else
|
||||
_Position = (float)(position / (double)Constants.SECOND);
|
||||
return _Position;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_Element != null)
|
||||
_Element.SeekSimple(Format.Time, SeekFlags.Accurate | SeekFlags.Flush, (long)(value * (double)Constants.SECOND));
|
||||
}
|
||||
}
|
||||
|
||||
public bool Paused
|
||||
{
|
||||
get { return _Element == null || _Element.TargetState == State.Paused; }
|
||||
set
|
||||
{
|
||||
if (value && _Element != null)
|
||||
_Element.SetState(State.Paused);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Playing
|
||||
{
|
||||
get { return _Element != null && (_Element.TargetState == State.Playing && !Finished); }
|
||||
set
|
||||
{
|
||||
if (value && _Element != null)
|
||||
_Element.SetState(State.Playing);
|
||||
}
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
while (_Element != null && _Element.Bus != null && _Element.Bus.HavePending())
|
||||
_OnMessage(_Element.Bus.Pop());
|
||||
|
||||
if (_Fading != null)
|
||||
{
|
||||
bool finished;
|
||||
Volume = _Fading.GetValue(out finished);
|
||||
if (finished)
|
||||
{
|
||||
switch (_AfterFadeAction)
|
||||
{
|
||||
case EStreamAction.Pause:
|
||||
Paused = true;
|
||||
break;
|
||||
case EStreamAction.Stop:
|
||||
Stop();
|
||||
break;
|
||||
case EStreamAction.Close:
|
||||
Close();
|
||||
break;
|
||||
}
|
||||
_Fading = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void _UpdateDuration()
|
||||
{
|
||||
_QueryingDuration = true;
|
||||
long duration = -1;
|
||||
while (duration < 0 && !Closed && !Finished && _Element != null)
|
||||
{
|
||||
if (_Element.QueryDuration(Format.Time, out duration))
|
||||
{
|
||||
_Duration = duration / (float)Constants.SECOND;
|
||||
_QueryingDuration = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,12 +19,6 @@ using System.Linq;
|
||||
using OpenTK.Audio;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using Vocaluxe.Base;
|
||||
using Vocaluxe.Lib.Sound.Playback.Decoder;
|
||||
using VocaluxeLib;
|
||||
|
||||
namespace Vocaluxe.Lib.Sound.Playback.OpenAL
|
||||
{
|
||||
@@ -352,497 +346,4 @@ namespace Vocaluxe.Lib.Sound.Playback.OpenAL
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
class COpenAlStream : IDisposable
|
||||
{
|
||||
private const int _BufferSize = 2048;
|
||||
private const int _BufferCount = 5;
|
||||
private const long _Bufsize = 50000L;
|
||||
|
||||
private Object _CloseMutex;
|
||||
|
||||
private int[] _Buffers;
|
||||
private int _State;
|
||||
private int _Source;
|
||||
private SFormatInfo _Format;
|
||||
|
||||
private bool _Initialized;
|
||||
private int _ByteCount = 4;
|
||||
private float _Volume = 1f;
|
||||
private float _VolumeMax = 1f;
|
||||
|
||||
private EStreamAction _AfterFadeAction;
|
||||
private CFading _Fading;
|
||||
|
||||
private readonly Stopwatch _Timer = new Stopwatch();
|
||||
|
||||
private Closeproc _Closeproc;
|
||||
private int _StreamID;
|
||||
private IAudioDecoder _Decoder;
|
||||
private float _BytesPerSecond;
|
||||
private bool _NoMoreData;
|
||||
|
||||
private bool _FileOpened;
|
||||
|
||||
private bool _Waiting;
|
||||
private bool _Skip;
|
||||
|
||||
private bool _Loop;
|
||||
private float _Duration;
|
||||
private float _CurrentTime;
|
||||
private float _TimeCode;
|
||||
|
||||
private bool _Paused;
|
||||
|
||||
private CRingBuffer _Data;
|
||||
private float _SetStart;
|
||||
private float _Start;
|
||||
private bool _SetLoop;
|
||||
private bool _SetSkip;
|
||||
private bool _Terminated;
|
||||
|
||||
private readonly Thread _DecoderThread;
|
||||
|
||||
private AutoResetEvent _EventDecode = new AutoResetEvent(false);
|
||||
|
||||
private readonly Object _MutexData = new Object();
|
||||
private readonly Object _MutexSyncSignals = new Object();
|
||||
|
||||
public COpenAlStream()
|
||||
{
|
||||
_Initialized = false;
|
||||
_DecoderThread = new Thread(_Execute) {Name = "OpenAL Decode"};
|
||||
}
|
||||
|
||||
public void Free(Closeproc closeProc, int streamID, Object closeMutex)
|
||||
{
|
||||
_Closeproc = closeProc;
|
||||
_StreamID = streamID;
|
||||
_Terminated = true;
|
||||
_CloseMutex = closeMutex;
|
||||
}
|
||||
|
||||
public float Length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_FileOpened)
|
||||
return _Duration;
|
||||
|
||||
return 0f;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Finished
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_MutexData)
|
||||
{
|
||||
return _NoMoreData && _Data.BytesNotRead == 0L;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float Volume
|
||||
{
|
||||
get { return _Volume * 100f; }
|
||||
set
|
||||
{
|
||||
lock (_MutexData)
|
||||
{
|
||||
_Volume = value / 100f;
|
||||
if (_Volume < 0f)
|
||||
_Volume = 0f;
|
||||
|
||||
if (_Volume > 1f)
|
||||
_Volume = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float VolumeMax
|
||||
{
|
||||
get { return _VolumeMax * 100f; }
|
||||
set
|
||||
{
|
||||
lock (_MutexData)
|
||||
{
|
||||
_VolumeMax = value / 100f;
|
||||
if (_VolumeMax < 0f)
|
||||
_VolumeMax = 0f;
|
||||
|
||||
if (_VolumeMax > 1f)
|
||||
_VolumeMax = 1f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float Position
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Finished)
|
||||
_Timer.Stop();
|
||||
//TODO: Why not use Decoder.GetPosition()?
|
||||
return _CurrentTime + _Timer.ElapsedMilliseconds / 1000f;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Paused
|
||||
{
|
||||
get { return _Paused; }
|
||||
set
|
||||
{
|
||||
_Paused = value;
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
if (_Paused)
|
||||
{
|
||||
_Timer.Stop();
|
||||
AL.SourceStop(_Source);
|
||||
}
|
||||
else
|
||||
{
|
||||
_Timer.Start();
|
||||
_EventDecode.Set();
|
||||
AL.SourcePlay(_Source);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Fade(float targetVolume, float fadeTime)
|
||||
{
|
||||
_Fading = new CFading(_Volume, targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Nothing;
|
||||
}
|
||||
|
||||
public void FadeAndPause(float targetVolume, float fadeTime)
|
||||
{
|
||||
Fade(targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Pause;
|
||||
}
|
||||
|
||||
public void FadeAndStop(float targetVolume, float fadeTime, Closeproc closeProc, int streamID)
|
||||
{
|
||||
_Closeproc = closeProc;
|
||||
_StreamID = streamID;
|
||||
Fade(targetVolume, fadeTime);
|
||||
_AfterFadeAction = EStreamAction.Stop;
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
Paused = false;
|
||||
_AfterFadeAction = EStreamAction.Nothing;
|
||||
AL.SourcePlay(_Source);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
AL.SourceStop(_Source);
|
||||
Skip(0f);
|
||||
}
|
||||
|
||||
public bool Loop
|
||||
{
|
||||
get { return _SetLoop; }
|
||||
set { _SetLoop = value; }
|
||||
}
|
||||
|
||||
public int Open(string fileName)
|
||||
{
|
||||
if (_FileOpened)
|
||||
return -1;
|
||||
|
||||
if (!File.Exists(fileName))
|
||||
return -1;
|
||||
|
||||
_Decoder = new CAudioDecoderFFmpeg();
|
||||
_Decoder.Init();
|
||||
|
||||
try
|
||||
{
|
||||
_Source = AL.GenSource();
|
||||
_Buffers = new int[_BufferCount];
|
||||
for (int i = 0; i < _BufferCount; i++)
|
||||
_Buffers[i] = AL.GenBuffer();
|
||||
|
||||
_State = 0;
|
||||
//AL.SourceQueueBuffers(_source, _buffers.Length, _buffers);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
_Initialized = false;
|
||||
CLog.LogError("Error Init OpenAL Playback");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_Decoder.Open(fileName);
|
||||
_Duration = _Decoder.GetLength();
|
||||
|
||||
_Format = _Decoder.GetFormatInfo();
|
||||
_ByteCount = 2 * _Format.ChannelCount;
|
||||
_BytesPerSecond = _Format.SamplesPerSecond * _ByteCount;
|
||||
_CurrentTime = 0f;
|
||||
_Timer.Reset();
|
||||
|
||||
var stream = new SAudioStreams(0) {Handle = _Buffers[0]};
|
||||
|
||||
if (stream.Handle != 0)
|
||||
{
|
||||
_FileOpened = true;
|
||||
_Data = new CRingBuffer(_Bufsize);
|
||||
_NoMoreData = false;
|
||||
_DecoderThread.Priority = ThreadPriority.Normal;
|
||||
_DecoderThread.Name = Path.GetFileName(fileName);
|
||||
_DecoderThread.Start();
|
||||
|
||||
return stream.Handle;
|
||||
}
|
||||
_Initialized = true;
|
||||
return -1;
|
||||
}
|
||||
|
||||
public bool Skip(float time)
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_SetStart = time;
|
||||
_SetSkip = true;
|
||||
}
|
||||
_EventDecode.Set();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#region Threading
|
||||
private void _DoSkip()
|
||||
{
|
||||
_Decoder.SetPosition(_Start);
|
||||
_CurrentTime = _Start;
|
||||
_TimeCode = _Start;
|
||||
_Timer.Reset();
|
||||
_Waiting = false;
|
||||
|
||||
lock (_MutexData)
|
||||
{
|
||||
_Data = new CRingBuffer(_Bufsize);
|
||||
_NoMoreData = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void _Execute()
|
||||
{
|
||||
while (!_Terminated)
|
||||
{
|
||||
_Waiting = false;
|
||||
if (_EventDecode.WaitOne(1) || !_Waiting)
|
||||
{
|
||||
if (_Skip)
|
||||
{
|
||||
_DoSkip();
|
||||
_Skip = false;
|
||||
}
|
||||
|
||||
_DoDecode();
|
||||
}
|
||||
if (!_Terminated)
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
if (_SetSkip)
|
||||
_Skip = true;
|
||||
|
||||
_SetSkip = false;
|
||||
|
||||
_Start = _SetStart;
|
||||
_Loop = _SetLoop;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_DoFree();
|
||||
}
|
||||
|
||||
private void _DoDecode()
|
||||
{
|
||||
if (!_FileOpened)
|
||||
return;
|
||||
|
||||
if (_Paused)
|
||||
return;
|
||||
|
||||
if (_Terminated)
|
||||
return;
|
||||
|
||||
float timecode;
|
||||
byte[] buffer;
|
||||
|
||||
bool doIt = false;
|
||||
lock (_MutexData)
|
||||
{
|
||||
if (_Bufsize - 10000L > _Data.BytesNotRead)
|
||||
doIt = true;
|
||||
}
|
||||
|
||||
if (!doIt)
|
||||
return;
|
||||
|
||||
_Decoder.Decode(out buffer, out timecode);
|
||||
|
||||
if (buffer == null)
|
||||
{
|
||||
if (_Loop)
|
||||
{
|
||||
lock (_MutexSyncSignals)
|
||||
{
|
||||
_CurrentTime = 0f;
|
||||
_Start = 0f;
|
||||
}
|
||||
|
||||
_DoSkip();
|
||||
}
|
||||
else
|
||||
_NoMoreData = true;
|
||||
return;
|
||||
}
|
||||
|
||||
lock (_MutexData)
|
||||
{
|
||||
_Data.Write(buffer);
|
||||
_TimeCode = timecode;
|
||||
}
|
||||
}
|
||||
|
||||
private void _DoFree()
|
||||
{
|
||||
if (_Initialized)
|
||||
{
|
||||
lock (_CloseMutex)
|
||||
{
|
||||
Stop();
|
||||
AL.DeleteSource(_Source);
|
||||
AL.DeleteBuffers(_Buffers);
|
||||
}
|
||||
_Decoder.Close();
|
||||
}
|
||||
|
||||
_Closeproc(_StreamID);
|
||||
}
|
||||
#endregion Threading
|
||||
|
||||
private void _Update()
|
||||
{
|
||||
if (_Fading != null)
|
||||
{
|
||||
bool finished;
|
||||
_Volume = _Fading.GetValue(out finished);
|
||||
if (finished)
|
||||
{
|
||||
switch (_AfterFadeAction)
|
||||
{
|
||||
case EStreamAction.Close:
|
||||
case EStreamAction.Stop:
|
||||
_Terminated = true;
|
||||
break;
|
||||
case EStreamAction.Pause:
|
||||
Paused = true;
|
||||
break;
|
||||
}
|
||||
_Fading = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void UploadData()
|
||||
{
|
||||
_Update();
|
||||
|
||||
if (_Paused)
|
||||
return;
|
||||
|
||||
int queuedCount;
|
||||
bool doit = true;
|
||||
AL.GetSource(_Source, ALGetSourcei.BuffersQueued, out queuedCount);
|
||||
|
||||
int processedCount = _BufferCount;
|
||||
if (queuedCount > 0)
|
||||
{
|
||||
AL.GetSource(_Source, ALGetSourcei.BuffersProcessed, out processedCount);
|
||||
doit = false;
|
||||
Console.WriteLine("Buffers Processed on Stream " + _Source + " = " + processedCount);
|
||||
if (processedCount < 1)
|
||||
return;
|
||||
}
|
||||
|
||||
var buf = new byte[_BufferSize];
|
||||
|
||||
lock (_MutexData)
|
||||
{
|
||||
while (processedCount > 0)
|
||||
{
|
||||
if (_Data.BytesNotRead >= buf.Length)
|
||||
{
|
||||
_Data.Read(buf);
|
||||
|
||||
|
||||
var b = new byte[2];
|
||||
for (int i = 0; i < buf.Length; i += _ByteCount)
|
||||
{
|
||||
b[0] = buf[i];
|
||||
b[1] = buf[i + 1];
|
||||
|
||||
b = BitConverter.GetBytes((Int16)(BitConverter.ToInt16(b, 0) * _Volume * _VolumeMax));
|
||||
buf[i] = b[0];
|
||||
buf[i + 1] = b[1];
|
||||
|
||||
if (_ByteCount == 4)
|
||||
{
|
||||
b[0] = buf[i + 2];
|
||||
b[1] = buf[i + 3];
|
||||
|
||||
b = BitConverter.GetBytes((Int16)(BitConverter.ToInt16(b, 0) * _Volume * _VolumeMax));
|
||||
buf[i + 2] = b[0];
|
||||
buf[i + 3] = b[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int buffer;
|
||||
if (!doit)
|
||||
buffer = AL.SourceUnqueueBuffer(_Source);
|
||||
else
|
||||
{
|
||||
buffer = _Buffers[queuedCount];
|
||||
queuedCount++;
|
||||
}
|
||||
|
||||
if (buffer != 0)
|
||||
{
|
||||
ALFormat alFormat = (_Format.ChannelCount == 2) ? ALFormat.Stereo16 : ALFormat.Mono16;
|
||||
AL.BufferData(buffer, alFormat, buf, buf.Length, _Format.SamplesPerSecond);
|
||||
Console.WriteLine("Write to Buffer: " + buffer);
|
||||
AL.SourceQueueBuffer(_Source, buffer);
|
||||
}
|
||||
}
|
||||
processedCount--;
|
||||
}
|
||||
AL.GetSource(_Source, ALGetSourcei.SourceState, out _State);
|
||||
if ((ALSourceState)_State != ALSourceState.Playing)
|
||||
AL.SourcePlay(_Source);
|
||||
}
|
||||
|
||||
_CurrentTime = _TimeCode - _Data.BytesNotRead / _BytesPerSecond - 0.1f;
|
||||
_Timer.Reset();
|
||||
_Timer.Start();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_EventDecode.Close();
|
||||
_EventDecode = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,10 +53,7 @@ namespace Vocaluxe.Lib.Sound.Record.DirectSound
|
||||
{
|
||||
using (var ds = new DirectSoundCapture(dev.DriverGuid))
|
||||
{
|
||||
var device = new CRecordDevice {Driver = dev.DriverGuid.ToString(), ID = id, Name = dev.Description, Channels = ds.Capabilities.Channels};
|
||||
|
||||
if (device.Channels > 2)
|
||||
device.Channels = 2; //more are not supported in vocaluxe
|
||||
var device = new CRecordDevice(id,dev.DriverGuid.ToString(), dev.Description, ds.Capabilities.Channels);
|
||||
|
||||
_Devices.Add(device);
|
||||
|
||||
|
||||
@@ -22,13 +22,25 @@ namespace Vocaluxe.Lib.Sound.Record
|
||||
{
|
||||
class CRecordDevice
|
||||
{
|
||||
public int ID;
|
||||
public string Name;
|
||||
public string Driver;
|
||||
public readonly int ID;
|
||||
public readonly string Name;
|
||||
public readonly string Driver;
|
||||
|
||||
public int Channels;
|
||||
public readonly int Channels;
|
||||
public int PlayerChannel1;
|
||||
public int PlayerChannel2;
|
||||
|
||||
public CRecordDevice(int id, string name, string driver, int channels)
|
||||
{
|
||||
ID = id;
|
||||
Name = name;
|
||||
Driver = driver;
|
||||
|
||||
if (channels > 2)
|
||||
channels = 2; //more are not supported in vocaluxe
|
||||
|
||||
Channels = channels;
|
||||
}
|
||||
}
|
||||
|
||||
struct SMicConfig
|
||||
|
||||
@@ -71,10 +71,7 @@ namespace Vocaluxe.Lib.Sound.Record.PortAudio
|
||||
CPortAudio.SPaDeviceInfo info = CPortAudio.PaGetDeviceInfo(i);
|
||||
if (info.HostApi == hostAPI && info.MaxInputChannels > 0)
|
||||
{
|
||||
var dev = new CRecordDevice {ID = i, Name = info.Name, Driver = info.Name + i, Channels = info.MaxInputChannels};
|
||||
|
||||
if (dev.Channels > 2)
|
||||
dev.Channels = 2; //more are not supported in vocaluxe
|
||||
var dev = new CRecordDevice( i, info.Name,info.Name + i, info.MaxInputChannels);
|
||||
|
||||
_Devices.Add(dev);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user