libFLAC エンコーディングの例を C# に移植しようとしたところ、次のコードが思いつきました。
public class LibFLAC {
public static void Test() {
string inputPath = Path.Combine("D:\\", "_", "test.pcm");
string outputPath = Path.Combine("D:\\", "_", "test.flac");
uint channels = 2;
uint bitsPerSample = 16;
uint sampleRate = 44100;
IntPtr encoder = FLAC__stream_encoder_new();
if (encoder == IntPtr.Zero) throw new Exception("Encoder: NEW failed");
bool ok = true;
ok &= FLAC__stream_encoder_set_channels(encoder, channels);
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, bitsPerSample);
ok &= FLAC__stream_encoder_set_sample_rate(encoder, sampleRate);
ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
// ok &= FLAC__stream_encoder_set_verify(encoder, true);
if (!ok) throw new Exception("Encoder: SET failed");
int status = FLAC__stream_encoder_init_file(encoder, outputPath, IntPtr.Zero, IntPtr.Zero);
if (status != 0) throw new Exception("Encoder: INIT FILE failed");
using (FileStream stream = new FileStream(inputPath, FileMode.Open, FileAccess.Read)) {
uint bps = bitsPerSample / 8;
byte[] buffer = new byte[channels * bps * 1024];
Int32[] pcm = new Int32[channels * 1024];
int read;
while ((read = stream.Read(buffer, 0, buffer.Length)) != 0) {
for (var i = 0; i < read / bps; i++) {
pcm[i] = (Int32) (((uint) buffer[i * 2 + 1] << 8) | (uint) buffer[i * 2]);
}
ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, (uint) (read / bps / channels));
if (!ok) throw new Exception("Encoder: PROCESS INTERLEAVED failed ::: " + FLAC__stream_encoder_get_state(encoder) + " ::: " + FLAC__stream_encoder_get_verify_decoder_state(encoder));
}
ok = FLAC__stream_encoder_finish(encoder);
if (!ok) throw new Exception("Encoder: FINISH failed");
FLAC__stream_encoder_delete(encoder);
encoder = IntPtr.Zero;
}
Console.WriteLine("\n\n\nDone");
Console.ReadKey();
}
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr FLAC__stream_encoder_new();
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern void FLAC__stream_encoder_delete(IntPtr encoder);
[DllImport("libFLAC", CallingConvention=CallingConvention.Cdecl)]
public static extern bool FLAC__stream_encoder_set_verify(IntPtr encoder, bool value);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern bool FLAC__stream_encoder_set_channels(IntPtr encoder, uint value);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern bool FLAC__stream_encoder_set_bits_per_sample(IntPtr encoder, uint value);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern bool FLAC__stream_encoder_set_sample_rate(IntPtr encoder, uint value);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern bool FLAC__stream_encoder_set_compression_level(IntPtr encoder, uint value);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern int FLAC__stream_encoder_init_file(IntPtr encoder, string filename, IntPtr progress_callback, IntPtr client_data);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern bool FLAC__stream_encoder_process_interleaved(IntPtr encoder, Int32[] buffer, uint samples);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern bool FLAC__stream_encoder_finish(IntPtr encoder);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern int FLAC__stream_encoder_get_state(IntPtr encoder);
[DllImport("libFLAC", CallingConvention = CallingConvention.Cdecl)]
public static extern int FLAC__stream_encoder_get_verify_decoder_state(IntPtr encoder);
}
ファイルは、test.pcm
WAV または RIFF ヘッダーのない生の PCM データであり、指定された形式 (2 チャネル、16 bps、および 44.1 kHz) です。
コードは動作し、FLAC は正常に再生されますが、作成されたファイルは元の wav とほぼ同じ大きさ (WAV: 47MB --> FLAC: 45MB) であり、最後に 200ms のノイズがあります。同じ設定で FLAC フロントエンド GUI を介して送信すると、35MB のファイルが得られるので、WAV は問題ないはずです。
また、有効にするFLAC__stream_encoder_set_verify
と、プログラムはすぐに失敗しFLAC__stream_encoder_process_interleaved
ます
FLAC__StreamEncoderState = 4
(VERIFY_MISMATCH_IN_AUDIO_DATA -ベリファイ デコーダーは、元のオーディオ信号とデコードされたオーディオ信号の間の不一致を検出しました。 ) およびFLAC__StreamDecoderState = 3
(READ_FRAME -デコーダーはフレームを読み取る準備ができているか、読み取り中です。 )
意味がないのはどれですか?
何かを見逃したり、変換を間違えたりしましたか?