I am making a windows forms that previews waveforms.
I use AudioFileReader.Read in the following:
A...When I first load the file and read through to save peak files for zoom preview
B...When I calculate FFT for the whole audio
C...When I draw the waveform
The wav/mp3 works fine, but when I load mp4, the Read in A and B works fine but C throws System.InvalidCastException.
Why does it happen only in C?
The exception and the codes are below. Thank you.
Exception:
例外がスローされました: 'System.InvalidCastException' (NAudio.dll の中)
System.InvalidCastException: 型 'System.__ComObject' の COM オブジェクトをインターフェイス型 'NAudio.MediaFoundation.IMFSourceReader' にキャストできません。IID '{70AE66F2-C809-4E4F-8915-BDCB406B7993}' が指定されたインターフェイスの COM コンポーネント上での QueryInterface 呼び出しのときに次のエラーが発生したため、この操作に失敗しました: インターフェイスがサポートされていません (HRESULT からの例外:0x80004002 (E_NOINTERFACE))。
場所 System.StubHelpers.StubHelpers.GetCOMIPFromRCW(Object objSrc, IntPtr pCPCMD, IntPtr& ppTarget, Boolean& pfNeedsRelease)
場所 NAudio.MediaFoundation.IMFSourceReader.SetCurrentPosition(Guid guidTimeFormat, IntPtr varPosition)
場所 NAudio.Wave.MediaFoundationReader.Reposition(Int64 desiredPosition)
場所 NAudio.Wave.MediaFoundationReader.Read(Byte[] buffer, Int32 offset, Int32 count)
場所 NAudio.Wave.SampleProviders.Pcm16BitToSampleProvider.Read(Single[] buffer, Int32 offset, Int32 count)
場所 NAudio.Wave.SampleProviders.MeteringSampleProvider.Read(Single[] buffer, Int32 offset, Int32 count)
場所 NAudio.Wave.SampleProviders.VolumeSampleProvider.Read(Single[] buffer, Int32 offset, Int32 sampleCount)
場所 NAudio.Wave.AudioFileReader.Read(Single[] buffer, Int32 offset, Int32 count)
場所 SengiriWave.SoundStream.GetNextPeak(Int32 id, Int64 samplesperpeak, Boolean withrms) 場所 D:\VisualStudio\SengiriWave\SoundStream.cs:行 303
場所 SengiriWave.DrawWave.PaintPeaksLines(SoundStream sound, Graphics graphics, Int32 skippx, Boolean withRMS) 場所 D:\VisualStudio\SengiriWave\DrawWave.cs:行 105
場所 SengiriWave.MainWindow.wave_Paint(Object sender, PaintEventArgs e) 場所 D:\VisualStudio\SengiriWave\MainWindow - wave.cs:行 194
Code: (Edited; simplified for easy copy paste)
public partial class Form1 : Form
{
List<AudioFileReader> streams = new List<AudioFileReader>();
int ch;
long fullsamples;
WaveFormat waveformat;
long fullms;
int block = 128;
int fftLength = 128;
public Form1()
{
InitializeComponent();
streams.Add(new AudioFileReader(/*Media file path*/));
ch = streams[0].WaveFormat.Channels;
fullsamples = (int)(streams[0].Length / streams[0].BlockAlign);
waveformat = streams[0].WaveFormat;
fullms = (int)(fullsamples * 1000 / waveformat.SampleRate);
backgroundWorker1.RunWorkerAsync();
}
//A
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker control = (BackgroundWorker)sender;
float[] write = new float[ch * 2];
int block = this.block * 2;
float[] sample = new float[block * ch];
for (int x = 0; x < 3; x++)
{
var writer = new WaveFileWriter("tempshrink" + x + ".wav", streams[x].WaveFormat);
streams[x].Position = 0;
int read = streams[x].Read(sample, 0, block * ch);
while (read != 0)
{
for (int b = 0; b < block; b++)
{
for (int c = 0; c < ch; c++)
{
int sampleindex = b * ch + c;
if (b == 0)
{
write[c] = sample[sampleindex];
write[c + ch] = sample[sampleindex];
}
else
{
write[c] = Math.Max(write[c], sample[sampleindex]);
write[c + ch] = Math.Min(write[c + ch], sample[sampleindex]);
}
}
}
//書き込み
for (int i = 0; i < write.Length; i++) writer.WriteSample(write[i]);
read = streams[x].Read(sample, 0, block * ch);
}
writer.Dispose();
streams.Add(new AudioFileReader("tempshrink" + x + ".wav"));
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
backgroundWorker2.RunWorkerAsync();
}
//B
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker control = (BackgroundWorker)sender;
AudioFileReader reader = streams[0];
reader.Position = 0;
int yoko = (int)(fullsamples / fftLength);
int tate = fftLength / 2;
int stride = (yoko % 4 == 0) ? yoko : (yoko / 4 + 1) * 4;
byte[] result = new byte[stride * tate];
byte[][] spec = new byte[yoko][];
int m = (int)Math.Log(fftLength, 2);
int bundle = 10;
Complex[] buffer = new Complex[fftLength];
int count = 0;
int readoncelength = fftLength * ch * bundle;
float[] sample = new float[readoncelength];
while (reader.Read(sample, 0, readoncelength) != 0)
{
for (int i = 0; i < bundle; i++)
{
int timex = count * bundle + i;
if (timex >= yoko) break;
for (int r = 0; r < fftLength; r++)
{
int index = (i * fftLength + r) * ch;
if (ch == 2) sample[index] = (sample[index] + sample[index + 1]) / 2;
buffer[r].X = sample[index] * (float)FastFourierTransform.HammingWindow(r, fftLength);
buffer[r].Y = 0.0f;
}
FastFourierTransform.FFT(true, m, buffer);
spec[timex] = new byte[tate];
for (int k = 0; k < tate; k++)
{
double diagonal = Math.Sqrt(buffer[k].X * buffer[k].X + buffer[k].Y * buffer[k].Y);
double intensityDB = 10.0 * Math.Log10(diagonal);
const double minDB = -50.0;
double percent = (intensityDB < minDB) ? 1.0 : intensityDB / minDB;
result[timex + (tate - 1 - k) * stride] = (byte)(255f * percent / 16);
spec[timex][k] = (byte)(255f * percent);
}
}
count++;
}
e.Result = result;
}
private void backgroundWorker2_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
timer1.Enabled = true;
}
//
private void timer1_Tick(object sender, EventArgs e)
{
float[] samples = new float[2];
//Throws Exception Here
while (streams[0].Read(samples, 0, 2)!=0)
{
}
}
}
Most likely because you are accessing it from different threads. The underlying APIs that NAudio is calling require access from the same thread a COM object was created on.
User contributions licensed under CC BY-SA 3.0