我开发了 Xamarin Android应用,允许用户通过AudioRecord
录制来自 micro 的声音,并将其写入.wav 文件中,并显示相关的频谱图。频谱图由SciChart库显示。
当我分别测试文件写作和频谱图显示时,一切正常。
但是,如果我尝试同时使用它们,则会遇到一些问题:文件写得很好,但不是“正确”。 文件提供的声音似乎加速了,并且缺少一些音频缓冲区。
从Activity
上的按钮开始开始:
((Button)FindViewById(Resource.Id.btnStart)).Click += async delegate
{
isRecording = true;
EnableButtons(true);
audioService = new WavAudioService();
audioService.samplesUpdated += AudioService_samplesUpdated;
audioService.StartRecording();
};
在AudioService
中,此初始化 AudioRecord
:
public async Task StartRecording()
{
audioRecord = new AudioRecord(AudioSource.Mic, 44100, ChannelIn.Mono, Android.Media.Encoding.Pcm16bit, buffer);
if (audioRecord.State == State.Initialized)
{
audioRecord.StartRecording();
}
isRecording = true;
recordingThread = new System.Threading.Thread(new ThreadStart(
WriteAudioDataToFile
));
recordingThread.Priority = System.Threading.ThreadPriority.Normal;
recordingThread.Start();
}
写入时文件,而AudioRecord
正在记录时:
private void WriteAudioDataToFile()
{
byte[] data = new byte[bufferSize];
string filename = GetTempFilename();
FileOutputStream fos = null;
try
{
fos = new FileOutputStream(filename);
}
catch (Java.IO.FileNotFoundException e)
{
// ...
}
int read = 0;
if (null != fos)
{
while (isRecording)
{
read = audioRecord.Read(data, 0, bufferSize);
int[] bytesAsInts = Array.ConvertAll(data, c => (int)c);
// call to FFT
var res = FFT(bytesAsInts);
if ((int)RecordStatus.ErrorInvalidOperation != read)
{
try
{
fos.Write(data);
}
catch (Java.IO.IOException e)
{
// ...
}
}
}
try
{
fos.Close();
}
catch (Java.IO.IOException e)
{
// ...
}
}
}
byte[]
已转换为int[]
,供FFT()
计算使用:
public async Task<int[]> FFT(int[] y)
{
var input = new AForge.Math.Complex[y.Length];
for (int i = 0; i < y.Length; i++)
{
input[i] = new AForge.Math.Complex(y[i], 0);
}
FourierTransform.FFT(input, FourierTransform.Direction.Forward);
var result = new int[y.Length / 2];
// getting magnitude
for (int i = 0; i < y.Length / 2 - 1; i++)
{
var current = Math.Sqrt(input[i].Re * input[i].Re + input[i].Im * input[i].Im);
current = Math.Log10(current) * 10;
result[i] = (int)current;
}
samplesUpdated(this, new SamplesUpdatedEventArgs(result));
return result;
}
结果被发送到Activity
上的委托方法:
private async void AudioService_samplesUpdated(object sender, System.EventArgs e)
{
var audioService = (WavAudioService)sender;
if (token.IsCancellationRequested)
{
audioService.StopRecording();
return;
}
var arguments = e as SamplesUpdatedEventArgs;
if (arguments != null)
{
var samples = arguments.UpdatedSamples;
if (samples.Length < (samplesCount / 2))
{
return;
}
UpdateHeatmapDataSeries(samples);
}
}
最后,UpdateHeatmapDataSeries()
更新光谱图显示的值:
public async void UpdateHeatmapDataSeries(int[] data)
{
var spectrogramSize = width * height;
var fftSize = data.Length;
var offset = spectrogramSize - fftSize;
try
{
Array.Copy(Data, fftSize, Data, 0, offset);
Array.Copy(data, 0, Data, offset, fftSize);
heatmapSeries.UpdateZValues(Data);
}
catch (System.Exception e)
{
// ...
}
}
如果我将通话从UpdateHeatmapDataSeries()
移至AudioService_samplesUpdated()
,我将不再遇到以下问题: 文件提供了“正确”的声音 。
我试图添加一些Threads
来管理FFT()
或UpdateHeatmapDataSeries()
,但是 这并没有改变 :< / p>
private void WriteAudioDataToFile()
{
// ...
while (isRecording)
{
read = audioRecord.Read(data, 0, bufferSize);
int[] bytesAsInts = Array.ConvertAll(data, c => (int)c);
samplesUpdatedThread = new Thread(() => FFT(bytesAsInts));
samplesUpdatedThread.Start();
if ((int)RecordStatus.ErrorInvalidOperation != read)
{
try
{
fos.Write(data);
}
catch (Java.IO.IOException e)
{
// ...
}
}
}
// ...
}
private async void AudioService_samplesUpdated(object sender, System.EventArgs e)
{
// ...
var samples = arguments.UpdatedSamples;
if (samples.Length < (samplesCount / 2))
{
return;
}
System.Threading.Thread thread = new System.Threading.Thread(() => UpdateHeatmapDataSeries(samples));
thread.Start();
}
我忘记了什么吗?我该如何解决?