Beep on detection: fire-and-forget OutputStream, input keeps flowing
This commit is contained in:
@@ -11,6 +11,8 @@ const int Channels = 1;
|
|||||||
const uint BlockFrames = WakewordModel.FrameSamples; // 1280
|
const uint BlockFrames = WakewordModel.FrameSamples; // 1280
|
||||||
const float Threshold = 0.5f;
|
const float Threshold = 0.5f;
|
||||||
const double CooldownSeconds = 1.0;
|
const double CooldownSeconds = 1.0;
|
||||||
|
const double BeepHz = 880.0;
|
||||||
|
const double BeepSeconds = 0.2;
|
||||||
|
|
||||||
// .NET-side mirror for any readers that go through Environment.GetEnvironmentVariable,
|
// .NET-side mirror for any readers that go through Environment.GetEnvironmentVariable,
|
||||||
// AND libc setenv so PortAudio / onnxruntime (which use getenv()) see the values.
|
// AND libc setenv so PortAudio / onnxruntime (which use getenv()) see the values.
|
||||||
@@ -79,6 +81,7 @@ try
|
|||||||
using var stream = new Stream(
|
using var stream = new Stream(
|
||||||
inParams, null, SampleRate, BlockFrames, StreamFlags.NoFlag, callback, IntPtr.Zero);
|
inParams, null, SampleRate, BlockFrames, StreamFlags.NoFlag, callback, IntPtr.Zero);
|
||||||
stream.Start();
|
stream.Start();
|
||||||
|
short[] beepBuffer = MakeBeep(BeepHz, BeepSeconds, SampleRate);
|
||||||
Console.WriteLine("Listening. Say 'alexa'. Ctrl-C to exit.");
|
Console.WriteLine("Listening. Say 'alexa'. Ctrl-C to exit.");
|
||||||
|
|
||||||
var sw = Stopwatch.StartNew();
|
var sw = Stopwatch.StartNew();
|
||||||
@@ -95,7 +98,7 @@ try
|
|||||||
{
|
{
|
||||||
Console.WriteLine($"DETECTED alexa score={score:0.000} t={now.TotalSeconds:0.0}s");
|
Console.WriteLine($"DETECTED alexa score={score:0.000} t={now.TotalSeconds:0.0}s");
|
||||||
lastTrigger = now;
|
lastTrigger = now;
|
||||||
// Beep is added in Task 5.
|
FireAndForgetBeep(device, beepBuffer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,6 +133,71 @@ static int FindUsbDevice()
|
|||||||
return -1; // unreachable
|
return -1; // unreachable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static short[] MakeBeep(double freqHz, double durationS, int sampleRate)
|
||||||
|
{
|
||||||
|
int n = (int)(sampleRate * durationS);
|
||||||
|
var buf = new short[n];
|
||||||
|
for (int i = 0; i < n; i++)
|
||||||
|
{
|
||||||
|
double t = i / (double)sampleRate;
|
||||||
|
double v = 0.3 * Math.Sin(2.0 * Math.PI * freqHz * t);
|
||||||
|
buf[i] = (short)(v * short.MaxValue);
|
||||||
|
}
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FireAndForgetBeep(int device, short[] beepBuffer)
|
||||||
|
{
|
||||||
|
int offset = 0;
|
||||||
|
var done = new ManualResetEventSlim(false);
|
||||||
|
|
||||||
|
var outParams = new StreamParameters
|
||||||
|
{
|
||||||
|
device = device,
|
||||||
|
channelCount = 1,
|
||||||
|
sampleFormat = SampleFormat.Int16,
|
||||||
|
suggestedLatency = PortAudio.GetDeviceInfo(device).defaultLowOutputLatency,
|
||||||
|
hostApiSpecificStreamInfo = IntPtr.Zero,
|
||||||
|
};
|
||||||
|
|
||||||
|
Stream.Callback playCb = (IntPtr _, IntPtr output, uint frameCount,
|
||||||
|
ref StreamCallbackTimeInfo _2, StreamCallbackFlags _3, IntPtr _4) =>
|
||||||
|
{
|
||||||
|
int remaining = beepBuffer.Length - offset;
|
||||||
|
int take = (int)Math.Min(frameCount, (uint)remaining);
|
||||||
|
int silence = (int)frameCount - take;
|
||||||
|
unsafe
|
||||||
|
{
|
||||||
|
short* dst = (short*)output.ToPointer();
|
||||||
|
if (take > 0)
|
||||||
|
{
|
||||||
|
fixed (short* src = &beepBuffer[offset])
|
||||||
|
Buffer.MemoryCopy(src, dst, take * sizeof(short), take * sizeof(short));
|
||||||
|
offset += take;
|
||||||
|
}
|
||||||
|
for (int i = take; i < frameCount; i++) dst[i] = 0;
|
||||||
|
}
|
||||||
|
if (offset >= beepBuffer.Length)
|
||||||
|
{
|
||||||
|
done.Set();
|
||||||
|
return StreamCallbackResult.Complete;
|
||||||
|
}
|
||||||
|
return StreamCallbackResult.Continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
var stream = new Stream(
|
||||||
|
null, outParams, WakewordModel.SampleRate, 1024, StreamFlags.NoFlag, playCb, IntPtr.Zero);
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
done.Wait();
|
||||||
|
Thread.Sleep(200);
|
||||||
|
stream.Stop();
|
||||||
|
stream.Dispose();
|
||||||
|
done.Dispose();
|
||||||
|
});
|
||||||
|
stream.Start();
|
||||||
|
}
|
||||||
|
|
||||||
static class Libc
|
static class Libc
|
||||||
{
|
{
|
||||||
[DllImport("libc", EntryPoint = "setenv")]
|
[DllImport("libc", EntryPoint = "setenv")]
|
||||||
|
|||||||
Reference in New Issue
Block a user