2018/12/11(火) [n年前の日記]
#1 [tic80] TIC-80上でPCM再生できないか試行錯誤中その2
なかなかそれらしく鳴ってくれない…。
まあ、一応、今現在の作業手順や成果についてメモ。
まあ、一応、今現在の作業手順や成果についてメモ。
◎ サンプリングレート1920Hzのwavを用意する。 :
実験に使う、モノラル、16bit、サンプリングレート1920Hzのwavは、Audacity 2.2.2 を使って用意しした。
_「Audacity」無料の音声編集ソフト - 窓の杜
操作手順は以下。
今回は、以下の4種類の wav を用意した。
_hello_1920hz_992sample.wav
_crt_hey_1920hz_672sample.wav
_crt_ooo_1920hz_512sample.wav
_ohit_mono_1920hz_960sample.wav
_「Audacity」無料の音声編集ソフト - 窓の杜
操作手順は以下。
- Audacity で wav を開いて、左下の Project Rate (Hz) を 1920 に変更。
- トラック → リサンプリング → 1920 を指定して変換。
- 正規化する。エフェクト → Built-in → 正規化、を選び、最大振幅を正規化 = -1.0dbに。
- サンプル数が 32 の倍数になってないと後処理時に都合が悪いので、そのあたりは揃える。
- A. 不要な部分を選択して Deleteキーを叩いて削除して合わせてもいいし…。
- B. 必要な分を無音トラックを作って Mix してもいい。トラック → 新しく追加 → モノラルトラック、でトラックを追加後、ジェネレーター → Built-in → 無音 → 必要なサンプル数を入力して無音トラックを作ってから、全選択(Ctrl+A) → トラック → Mix → ミックスして作成。
- wavとして保存し直す。ファイル → Export → オーディオの書き出し → 保存wavファイル名を打ち込んで保存。
今回は、以下の4種類の wav を用意した。
_hello_1920hz_992sample.wav
_crt_hey_1920hz_672sample.wav
_crt_ooo_1920hz_512sample.wav
_ohit_mono_1920hz_960sample.wav
◎ 32ポイントずつ分割して出力。 :
Pythonスクリプトで、wav を32ポイントずつ分割して、音量4bitにしたバイト列データをテキスト出力。
動作環境・利用モジュールは、Windows10 x64 + Python 2.7.15 + Pydub 0.23.0 + Numpy 1.15.4。
使用スクリプトは以下。
_dump_divide_32sample.py
waveファイル名を指定して実行。
Luaスクリプトに貼り付けられるテキストが得られる。
動作環境・利用モジュールは、Windows10 x64 + Python 2.7.15 + Pydub 0.23.0 + Numpy 1.15.4。
使用スクリプトは以下。
_dump_divide_32sample.py
waveファイル名を指定して実行。
> python dump_divide_32sample.py crt_hey_1920hz_672sample.wav > temp.txt
Luaスクリプトに貼り付けられるテキストが得られる。
-- Input file : crt_hey_1920hz_672sample.wav -- Channel : 1 -- Sampling rate : 1920 Hz -- Duration : 350.000000 msec -- Sample length : 672 point -- N : 21 pcmtbl={ "88787777878888776776988978667599", "896855969a884684ab9937829c9916c3", "7b8a12bca60af4586bb04ca9815ea772", "5d97935b58c57738b986556c87a35a48", "c786656c78c468389a96835b59b79666", "5b78b477498a96945a5ab795566b88a4", "67499995765a79a576598996756a78a5", "77599895577a97855979b5674ab79438", "8bb4555cb7834b9aa3497bc4575bc575", "4bb7843ab8943aa9a3399aa4388aa448", "8aa448999449a8844ab7755bb5567bb3", "489a834bb7468ba549b7658a845aa747", "a9757a945aa748b76699559a758a747b", "8569847a8679758a7589649a669946a9", "57985896797688669868866886896688", "67977976896697797689669878768867", "87897788787698788689678788787788", "67768878878878777788787788787777", "87887787787777778788777788777777", "77777777777777777777777777777777", "77777777777777777777777777777777", }
◎ TIC-80上で再生。 :
TIC-80上で再生。ソースとticファイルは以下。
_pcmtest.lua
_pcmtest_20181212.zip
SFXエディタを開いて、以下のような設定にしておく。SFX ID 1番目の wave 設定を、8〜15まで順々に切り替えて、かつ、ループするように設定。
音階 B-2 を鳴らしても本来の60Hzから微妙にずれてるので、気休めかもしれないけどpitch設定も少しずらして、かつ、ループするようにしておく。
で。一応、以下のような動作になったのだけど…。
_pcmtest.tic.html
しかし、実に酷い音。元々のwavと聞き比べると、なんじゃこりゃ状態。
wavの段階では、サンプリングレート1920Hzのアレな音とは言え、それでもまだなんとか聞き取れなくもないけれど。TIC-80上で鳴らすと、もはや何を言ってるのかさっぱり分からん…。TIC-80が「ベラボー」「ミッソ」と喋ったらちょっと面白いかなと思ったけれど、現時点では正直かなり厳しいなと。
_pcmtest.lua
_pcmtest_20181212.zip
SFXエディタを開いて、以下のような設定にしておく。SFX ID 1番目の wave 設定を、8〜15まで順々に切り替えて、かつ、ループするように設定。
音階 B-2 を鳴らしても本来の60Hzから微妙にずれてるので、気休めかもしれないけどpitch設定も少しずらして、かつ、ループするようにしておく。
で。一応、以下のような動作になったのだけど…。
_pcmtest.tic.html
- ブラウザ上で実行できます。
- Z、X、C、Vキーのどれかを押せば再生されます。
しかし、実に酷い音。元々のwavと聞き比べると、なんじゃこりゃ状態。
wavの段階では、サンプリングレート1920Hzのアレな音とは言え、それでもまだなんとか聞き取れなくもないけれど。TIC-80上で鳴らすと、もはや何を言ってるのかさっぱり分からん…。TIC-80が「ベラボー」「ミッソ」と喋ったらちょっと面白いかなと思ったけれど、現時点では正直かなり厳しいなと。
◎ 処理内容について補足。 :
再生時に読み取ってるはずの波形メモリと、書き換えてる最中の波形メモリが一緒だとノイズが入ったりするのかなと想像して、一番最初の書き換え時はともかく、その後は読み出しと書き換えの波形メモリをずらすようにしてみたのだけど、全く効果が無く。
まあ、ハードウェアで処理する場合なら、そういう対策が有効だったりする時もあるけれど、この場合ソフトウェアで実現してるソレだから、そういうアレコレでノイズの有無が変わるわけでもないのだろう…。
まあ、ハードウェアで処理する場合なら、そういう対策が有効だったりする時もあるけれど、この場合ソフトウェアで実現してるソレだから、そういうアレコレでノイズの有無が変わるわけでもないのだろう…。
◎ 既にPCM再生を試してる方が居た。 :
公式サイトのPlayページを眺めていたら、以下のプログラムがPCM再生を試していた。
_Play BASIC PCM @ 1.92 KHZ in TIC-80
ソースを眺めたけれど、以下の部分がよく分からない…。
ただ、 _RAM - nesbox/TIC-80 Wiki を眺めているうちに、なんとなく分かってきた。
仕組みが分かったので、同じ方法で自分も鳴らしてみた。
_ブラウザ上で実行 : pcmtest2.tic.html
_ソース : pcmtest2.lua
_ticファイル : pcmtest2_20181212.zip
波形メモリを書き換えていくソレと比べて、音質はほとんど変わらなかった…。現状の TIC-80 では、これが限界なのかもしれない…。
_Play BASIC PCM @ 1.92 KHZ in TIC-80
ソースを眺めたけれど、以下の部分がよく分からない…。
poke(0xFF9C,60) for i=0,32 do poke4(0x1FF3B+i,peek4(baseAddr+i+((t%length)*33))) end
ただ、 _RAM - nesbox/TIC-80 Wiki を眺めているうちに、なんとなく分かってきた。
- poke(0xFF9C, 60) は、SOUND REGISTER の周波数を設定してる。この場合は 60Hz を指定してる。はず。たぶん。
- poke() は1byteを書き換えて、poke4() は 4bit を書き換える。
- poke4()に渡すアドレスは、poke()で使うアドレスを2倍したものになる。つまり、0x1FF3B の指定は、本来のアドレスなら 0xFF9D * 2 + 1 を指定してる。この場合、SOUND REGISTER の volume値のあたりから書き換え始めている、ような気がする。
- volume の次のアドレスからは、波形を記録する領域になっていたらしい。音量4bit が 32個、つまり 16byte が並ぶ。
仕組みが分かったので、同じ方法で自分も鳴らしてみた。
_ブラウザ上で実行 : pcmtest2.tic.html
_ソース : pcmtest2.lua
_ticファイル : pcmtest2_20181212.zip
波形メモリを書き換えていくソレと比べて、音質はほとんど変わらなかった…。現状の TIC-80 では、これが限界なのかもしれない…。
◎ 2018/12/12追記。 :
一部ループ処理がバグってたのと、データを文字列で持ったほうがソースが短くなりそうだったので、修正して再アップロードしておいた。しかし、音質はさほど変わらず。
[ ツッコむ ]
#2 [pc] soxを試用
sox というツールを使って、サンプリングレートを1920Hzにできそうか、リサンプリングを試してみたり。環境は Windows10 x64 + sox 14.4.2。
_SoX - Sound eXchange | HomePage
-r N でサンプリングレートの指定、--norm でノーマライズの指定、だろうか。
-b N オプションで8bit等に変換できるようで。もしや 4bit も変換できるのかなと試してみたけれど。
出力された wav は、Python + Pydub ではエラーが出て開けなかった。ffmpegが呼び出されたものの変換不能と言われてしまう。
真空波動研Lite というツールで確認してみたところ…。
余談だけど、ADPCM というのは、絶対値じゃなくて前の値からの差分を記録していく方法。DPCMは差分の変化幅が一定だけど、ADPCMは差分の大小で幅を変えて記録する、のではなかったかな…。以下のページの図が分かりやすい、ような気がする。
_ADPCMの実験
_音声圧縮処理の基本 ―― 音楽CDやWAVファイルで使われている波形符号化方式|Tech Village (テックビレッジ) / CQ出版株式会社
_SoX - Sound eXchange | HomePage
-r N でサンプリングレートの指定、--norm でノーマライズの指定、だろうか。
sox input.wav -r 1920 --norm output.wavこれで変換できた。変換後の音質は、Audacityのソレと似た感じ。
-b N オプションで8bit等に変換できるようで。もしや 4bit も変換できるのかなと試してみたけれど。
sox input.wav -r 1920 -b 4 --norm output.wav
出力された wav は、Python + Pydub ではエラーが出て開けなかった。ffmpegが呼び出されたものの変換不能と言われてしまう。
真空波動研Lite というツールで確認してみたところ…。
[out.wav] Microsoft ADPCM 1.92kHz 4Bit 1ch 7.86kb/s [RIFF(WAVE)] 00:00:00.520 (0.520sec) / 602Bytes 真空波動研Lite 160508 / DLL 160508 Unicode4bitではあるけれど、PCMじゃなくてADPCMになっているようで。wavファイルは、そんなフォーマットも含めることができるのか…。
余談だけど、ADPCM というのは、絶対値じゃなくて前の値からの差分を記録していく方法。DPCMは差分の変化幅が一定だけど、ADPCMは差分の大小で幅を変えて記録する、のではなかったかな…。以下のページの図が分かりやすい、ような気がする。
_ADPCMの実験
_音声圧縮処理の基本 ―― 音楽CDやWAVファイルで使われている波形符号化方式|Tech Village (テックビレッジ) / CQ出版株式会社
[ ツッコむ ]
以上、1 日分です。