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 float Threshold = 0.5f;
|
||||
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,
|
||||
// AND libc setenv so PortAudio / onnxruntime (which use getenv()) see the values.
|
||||
@@ -79,6 +81,7 @@ try
|
||||
using var stream = new Stream(
|
||||
inParams, null, SampleRate, BlockFrames, StreamFlags.NoFlag, callback, IntPtr.Zero);
|
||||
stream.Start();
|
||||
short[] beepBuffer = MakeBeep(BeepHz, BeepSeconds, SampleRate);
|
||||
Console.WriteLine("Listening. Say 'alexa'. Ctrl-C to exit.");
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
@@ -95,7 +98,7 @@ try
|
||||
{
|
||||
Console.WriteLine($"DETECTED alexa score={score:0.000} t={now.TotalSeconds:0.0}s");
|
||||
lastTrigger = now;
|
||||
// Beep is added in Task 5.
|
||||
FireAndForgetBeep(device, beepBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -130,6 +133,71 @@ static int FindUsbDevice()
|
||||
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
|
||||
{
|
||||
[DllImport("libc", EntryPoint = "setenv")]
|
||||
|
||||
Reference in New Issue
Block a user