0. はじめに
Raspberry Pi Pico で CircuitPython を使って、WAVファイルを再生するとき、『ValueError: fmtチャンクの後にdataチャンクが続かなければなりません』のエラーとなって再生できないWAVファイルが存在する。
このエラーの対応策を調べました。
WAVファイルの再生は、Adafruitのサイトで紹介されている、下記コードで確認。
(⭐️の箇所でエラーが起こる)
Adafruit CircuitPython 9.0.4 on 2024-04-16; Raspberry Pi Pico with rp2040
1. エラーの原因
一口に WAVファイルといっても、ファイルの中身(ファイルフォーマット)には、何パターンもあり、その一部のファイルフォーマットに対応していないことが原因のようです。
ネットに公開されているフリー音源や、オンラインのメディア変換(MP3→WAV)で作ったWAVファイルでも、このエラーになるファイルがあります。もちろん、普通に再生できるWAVファイルもあります。
これに関しては深追いはしていません。(コーデックの違い??)
2. 対応策
ffmpeg
コマンドでファイルを修復します(修復という表現が正しいのか分かりません)。
ffmpegコマンドに次のオプションを指定します。
ffmpeg -i "original.wav" -bitexact -acodec pcm_s16le -ac 2 -ar 16000 -map_metadata -1 "repaired.wav"
or
ffmpeg -i "original.mp3" -bitexact -acodec pcm_s16le -ac 2 -ar 16000 -map_metadata -1 "converted.wav"
モノラル音源の場合は、-ac 2
を-ac 1
にする。
出典;
2.1 修復前後のファイルの違い
$ ffmpeg -hide_banner -i hapyou2.mp3
[mp3 @ 0x11ce06400] Estimating duration from bitrate, this may be inaccurate
Input #0, mp3, from 'hapyou2.mp3':
Duration: 00:00:05.12, start: 0.000000, bitrate: 128 kb/s
Stream #0:0: Audio: mp3 (mp3float), 44100 Hz, stereo, fltp, 128 kb/s
At least one output file must be specified
$ ffmpeg -hide_banner -i hapyou2.wav
[aist#0:0/pcm_s16le @ 0x122606120] Guessed Channel Layout: stereo
Input #0, wav, from 'hapyou2.wav':
Metadata:
encoder : Lavf59.27.100
Duration: 00:00:05.12, bitrate: 1411 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s
At least one output file must be specified
$ ffmpeg -hide_banner -i hapyou2.wav -bitexact -acodec pcm_s16le -ac 2 -ar 16000 -map_metadata -1 repaired.wav
[aist#0:0/pcm_s16le @ 0x12b6069d0] Guessed Channel Layout: stereo
Input #0, wav, from 'hapyou2.wav':
Metadata:
encoder : Lavf59.27.100
Duration: 00:00:05.12, bitrate: 1411 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (pcm_s16le (native) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, wav, to 'repaired.wav':
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, stereo, s16, 512 kb/s
Metadata:
encoder : Lavc pcm_s16le
[out#0/wav @ 0x600003120540] video:0KiB audio:320KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.013428%
size= 320KiB time=00:00:05.12 bitrate= 512.1kbits/s speed= 826x
$ ffmpeg -hide_banner -i repaired.wav
[aist#0:0/pcm_s16le @ 0x120e072c0] Guessed Channel Layout: stereo
Input #0, wav, from 'repaired.wav':
Duration: 00:00:05.12, bitrate: 512 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, stereo, s16, 512 kb/s
At least one output file must be specified
$ ffmpeg -hide_banner -i hapyou2.mp3 -bitexact -acodec pcm_s16le -ac 2 -ar 16000 -map_metadata -1 converted.wav
[mp3 @ 0x131e06d70] Estimating duration from bitrate, this may be inaccurate
Input #0, mp3, from 'hapyou2.mp3':
Duration: 00:00:05.12, start: 0.000000, bitrate: 128 kb/s
Stream #0:0: Audio: mp3 (mp3float), 44100 Hz, stereo, fltp, 128 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (mp3 (mp3float) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, wav, to 'converted.wav':
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, stereo, s16, 512 kb/s
Metadata:
encoder : Lavc pcm_s16le
[out#0/wav @ 0x6000024f4600] video:0KiB audio:320KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.013428%
size= 320KiB time=00:00:05.12 bitrate= 512.1kbits/s speed= 678x
$ ffmpeg -hide_banner -i converted.wav
[aist#0:0/pcm_s16le @ 0x13a607340] Guessed Channel Layout: stereo
Input #0, wav, from 'converted.wav':
Duration: 00:00:05.12, bitrate: 512 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 16000 Hz, stereo, s16, 512 kb/s
At least one output file must be specified
①の再生できないWAVファイルと、②③の再生できるWAVファイルのffmpeg情報から、サンプリング周波数(とビットレート)の違いが見て取れる。
では、サンプリング周波数44.1KHzのWAVファイルがエラーとなるのか確認したが、問題なく再生できた。サンプリング周波数がエラーの原因では無い。
$ ffmpeg -hide_banner -i hapyou2.mp3 -bitexact -acodec pcm_s16le -ac 2 -ar 44100 -map_metadata -1 converted441.wav
[mp3 @ 0x12cf054f0] Estimating duration from bitrate, this may be inaccurate
Input #0, mp3, from 'hapyou2.mp3':
Duration: 00:00:05.12, start: 0.000000, bitrate: 128 kb/s
Stream #0:0: Audio: mp3 (mp3float), 44100 Hz, stereo, fltp, 128 kb/s
Stream mapping:
Stream #0:0 -> #0:0 (mp3 (mp3float) -> pcm_s16le (native))
Press [q] to stop, [?] for help
Output #0, wav, to 'converted441.wav':
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s
Metadata:
encoder : Lavc pcm_s16le
[out#0/wav @ 0x600001d4c000] video:0KiB audio:882KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 0.004872%
size= 882KiB time=00:00:05.12 bitrate=1411.3kbits/s speed= 584x
$ ffmpeg -hide_banner -i converted441.wav
[aist#0:0/pcm_s16le @ 0x147e072c0] Guessed Channel Layout: stereo
Input #0, wav, from 'converted441.wav':
Duration: 00:00:05.12, bitrate: 1411 kb/s
Stream #0:0: Audio: pcm_s16le ([1][0][0][0] / 0x0001), 44100 Hz, stereo, s16, 1411 kb/s
At least one output file must be specified
$ ffmpeg -version
ffmpeg version 7.0 Copyright (c) 2000-2024 the FFmpeg developers
built with Apple clang version 15.0.0 (clang-1500.3.9.4)
②③の再生できるWAVファイルの中身は同じかと想定したが、コンペアしてみたらそうではなかった。ファイルサイズは同じ。
$ cmp converted.wav repaired.wav
converted.wav repaired.wav differ: char 937, line 1
$ ls -ls converted.wav repaired.wav
648 -rw-r--r-- 1 user_name staff 327724 5 22 20:29 converted.wav
648 -rw-r--r-- 1 user_name staff 327724 5 22 20:38 repaired.wav
MicroPythonではエラーとならない
ちなみに、MicroPythonを使い、下記サイトのコードで再生すると、CircuitPythonではエラーとなるWAVファイルでも、エラーにならず再生できました。
CircuitPython(Adafruit)の実装の違いでしょうか。
MicroPython v1.22.2 on 2024-02-22; Raspberry Pi Pico W with RP2040
追伸
Raspberry Pi Pico のフラッシュメモリは2MBしか無いため、CircuitPython / MicroPythonのファームウェアを入れると、空き容量はわずかとなり、数秒のWAVファイルしか再生できない。
10秒で2MBぐらいになるため、大きいWAVファイルを再生するためには、外付けのSDカードから再生するしかない。
これについては、別の記事とする予定。