「mpglib.dllを使ったmp3再生」の編集履歴(バックアップ)一覧はこちら

mpglib.dllを使ったmp3再生」(2010/10/13 (水) 20:25:33) の最新版変更点

追加された行は緑色になります。

削除された行は赤色になります。

前回は素のwaveファイルお再生しました。 これを使えばほかのものでも応用ができます。 今回はmp3をやります。 mp3はデコーダやプレイやがあって今さらですけど、 ABでもできるんですよ。 今回使うのは定番のmpglib.dllです。 mpglib.dllのある場所[[http://mpesch3.de1.cc/misc.html]] こいつはABから使うことを想定していないしドキュメントも不親切です だから元となったmpg123というライブラリも調べてみるといいかもしれませんね。 まずこのDLLは3つの関数しかないので、簡単ですけど、便利な昨日がないので 自分で作ります。 ID3V2も自力で読み飛ばさないといけません。 **abmpglib.abp #asciiart(blockquote){ Const AUDIOBUFSIZE = 16384 Const SBLIMIT = 32 Const SSLIMIT = 18 Const SCALE_BLOCK = 12 /* Layer 2 */ Const MPG_MD_STEREO = 0 Const MPG_MD_JOINT_STEREO = 1 Const MPG_MD_DUAL_CHANNEL = 2 Const MPG_MD_MONO = 3 Const MAXFRAMESIZE = 1792 Const MP3_ERR = -1 Const MP3_OK = 0 Const MP3_NEED_MORE = 1 Type al_table bits As Word d As Word End Type Type frame stereo As Long jsbound As Long single As Long lsf As Long mpeg25 As Long header_change As Long lay As Long error_protection As Long bitrate_index As Long sampling_frequency As Long padding As Long extension As Long mode As Long mode_ext As Long copyright As Long original As Long emphasis As Long framesize As Long /* computed framesize */ II_sblimit As Long /* Layer 2 */ alloc As *al_table /* Layer 2 */ do_layer As VoidPtr /* Layer 2 */ End Type Type mpglib_buf pnt As *Byte size As Long pos As Long pnext As *mpglib_buf prev As *mpglib_buf End Type Type framebuf buf As *mpglib_buf pos As Long pnext As *frame prev As *frame End Type Type mpstr head As *mpglib_buf tail As *mpglib_buf bsize As Long framesize As Long fsizeold As Long fr As frame bsspace[ELM(2*(MAXFRAMESIZE+512))] As Byte /* MAXFRAMESIZE */ hybrid_block[ELM(2*2*SBLIMIT*SSLIMIT)] As Single hybrid_blc[ELM(2)] As Long header As DWord bsnum As Long synth_buffs[ELM(2*2*&h110)] As Single synth_bo As Long End Type Type ID3V2 ID3[2] As Byte majorversion As Byte revision As Byte flag As Byte size[3] As Byte End Type Declare Function InitMP3 CDECL Lib"mpglib.dll" Alias "_InitMP3" (mp As *mpstr) As Long Declare Sub ExitMP3 CDECL Lib"mpglib.dll" Alias "_ExitMP3" (mp As *mpstr) Declare Function decodeMP3 CDECL Lib"mpglib.dll" Alias "_decodeMP3" (mp As *mpstr, inmemory As *Byte, inmemsize As Long, outmemory As *Byte, outmemsize As Long, done As *Long) As Long Dim br_tbl[1,14] = [ [ 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320], [ 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160] ] As Long Dim rate_tbl[9] = [44100, 48000, 32000, 22050, 24000, 16000 , 11025 , 12000 , 8000, 0] As Long 'ID3V2のサイズを詰める Function unpack_sint28 (ptr As *Byte) As DWord Dim value As DWord If (ptr[0] And &h80) Then Exit Function value = value Or (ptr[0] And &h7f) value = (value << 7) Or (ptr[1] And &h7f) value = (value << 7) Or (ptr[2] And &h7f) value = (value << 7) Or (ptr[3] And &h7f) unpack_sint28 = value End Function Type ABMP3DEC_CTX mp As mpstr buf[AUDIOBUFSIZE] As Byte hF As HANDLE rate As Long ch As Long pcmb As DWord startpos As DWord more As Long status As Long End Type Dim mc As ABMP3DEC_CTX 'mp3ファイルを開いてデコード準備 Function OpenMp3(mp3file As *Byte) As Long Dim size As Long Dim out[8192] As Byte Dim len As Long Dim ret As Long Dim id3 As ID3V2 If mc.status = TRUE Then Exit Function ZeroMemory(VarPtr(mc), SizeOf(ABMP3DEC_CTX)) mc.hF = CreateFile(mp3file, GENERIC_READ, FILE_SHARE_READ, ByVal 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) If mc.hF = INVALID_HANDLE_VALUE Then Exit Function 'ID3V2 ReadFile(mc.hF, VarPtr(id3), SizeOf(ID3V2), VarPtr(len), ByVal 0) If strstr(id3.ID3, "ID3") Then If Not (id3.size[0] And &h80) Then mc.startpos = unpack_sint28(id3.size)+10 End If SetFilePointer(mc.hF, mc.startpos, 0, FILE_BEGIN) InitMP3(VarPtr(mc.mp)) '一度読み込んでフォーマットを取得 If ReadFile(mc.hF, mc.buf, 1024, VarPtr(len), ByVal 0) = FALSE Or len <= 0 Then '読み込みエラー End If ret = decodeMP3(VarPtr(mc.mp), mc.buf, len, out, 8192, VarPtr(size)) If ret <> MP3_OK Then 'デコードエラー End If mc.rate = rate_tbl[mc.mp.fr.sampling_frequency] mc.ch = mc.mp.fr.stereo 'リセット SetFilePointer(mc.hF, mc.startpos, 0, FILE_BEGIN) ExitMP3(VarPtr(mc.mp)) InitMP3(VarPtr(mc.mp)) mc.status = TRUE OpenMp3 = TRUE End Function 'サンプリングレート、チャンネル数を得る Function GetFormat(rate As *Long, ch As *Long) As Long If mc.status = FALSE Then Exit Function SetDWord(rate, mc.rate) SetDWord(ch, mc.ch) End Function 'デコードし、そのサイズを返す。 Function ReadMp3(pcm As *Byte, buflen As Long) As DWord Dim pos As DWord Dim len As DWord Dim siz As DWord Dim ret As Long If mc.status = FALSE Then Exit Function pos = 0 siz = 0 Do If mc.more = FALSE Then ret = ReadFile(mc.hF, mc.buf, 16384, VarPtr(len), ByVal 0) If ret = FALSE Or len = 0 Then *JUMP ret = decodeMP3(VarPtr(mc.mp), mc.buf, len, VarPtr(pcm[pos]), 8192, VarPtr(siz)) If ret = MP3_OK Then mc.more = TRUE End If While (ret = MP3_OK) pos = pos + siz If pos+8192 > buflen Then *JUMP ret = decodeMP3(VarPtr(mc.mp), NULL, 0, VarPtr(pcm[pos]), 8192, VarPtr(siz)) Wend mc.more = FALSE'次に読み込みが必要 Loop While pos+8192 < buflen *JUMP ReadMp3 = pos mc.pcmb = mc.pcmb + pos End Function '終わり Function CloseMp3() As Long If mc.status = FALSE Then Exit Function CloseHandle(mc.hF) ExitMP3(VarPtr(mc.mp)) mc.status = FALSE End Function } つぎに再生部 #asciiart(blockquote){ #include <api_mmsys.sbp> #include "abmpglib.abp" Declare Function waveOutOpen Lib "winmm" (phwo As *HWAVEOUT, uDeviceID As DWord, pwfx As *WAVEFORMATEX, dwCallback As DWord, dwInstance As DWord, fdwOpen As DWord) As MMRESULT Declare Function waveOutClose Lib "winmm" (hwo As HWAVEOUT) As MMRESULT Declare Function waveOutPrepareHeader Lib "winmm" (hwo As HWAVEOUT, pwh As *WAVEHDR, cbwh As DWord) As MMRESULT Declare Function waveOutUnprepareHeader Lib "winmm" (hwo As HWAVEOUT, pwh As *WAVEHDR, cbwh As DWord) As MMRESULT Declare Function waveOutWrite Lib "winmm" (hwo As HWAVEOUT, pwh As *WAVEHDR, cbwh As DWord) As MMRESULT Declare Function waveOutPause Lib "winmm" (hwo As HWAVEOUT) As MMRESULT Declare Function waveOutRestart Lib "winmm" (hwo As HWAVEOUT) As MMRESULT Declare Function waveOutReset Lib "winmm" (hwo As HWAVEOUT) As MMRESULT Declare Function waveOutGetPosition Lib "winmm" (hwo As HWAVEOUT, pmmt As *MMTIME, cbmmt As DWord) As MMRESULT Declare Function MulDiv Lib "kernel32" (nNumber As Long, nNumerator As Long, nDenominator As Long) As Long Const WAVE_MAPPER = (-1) Const CALLBACK_FUNCTION = &H00030000l Const WOM_OPEN = &H3BB Const WOM_CLOSE = &H3BC Const WOM_DONE = &H3BD Const WHDR_DONE = &H00000001 Const WHDR_PREPARED = &H00000002 Const WHDR_BEGINLOOP = &H00000004 Const WHDR_ENDLOOP = &H00000008 Const WHDR_INQUEUE = &H00000010 Const TIME_MS = &H0001 Const TIME_SAMPLES = &H0002 Const TIME_BYTES = &H0004 Const TIME_SMPTE = &H0008 Const TIME_MIDI = &H0010 Const TIME_TICKS = &H0020 TypeDef MMRESULT = DWord Typedef HWAVEOUT = VoidPtr Type WAVEHDR lpData As *Byte dwBufferLength As DWord dwBytesRecorded As DWord dwUser As DWord dwFlags As DWord dwLoops As DWord lpNext As *WAVEHDR reserved As *DWord End Type Type MMTIME wType As DWord u As DWord u2 As DWord End Type Class Mp3Player Private buffer[2] As *Byte hwo As HWAVEOUT wfe As WAVEFORMATEX switch As Long Function GetMp3Header() As Long Dim head[3] As Byte Dim r As DWord Dim c As DWord GetFormat(VarPtr(r), VarPtr(c)) wfe.wFormatTag = 1 wfe.nChannels = c wfe.nSamplesPerSec = r wfe.wBitsPerSample = 16 wfe.cbSize = Sizeof(WAVEFORMATEX) wfe.nBlockAlign = wfe.nChannels * wfe.wBitsPerSample/8 wfe.nAvgBytesPerSec = wfe.nSamplesPerSec * wfe.nBlockAlign GetMp3Header = 1 End Function Sub waveOutProc(hwo As HWAVEOUT, uMsg As DWord, dwInstance As *DWord, dwParam1 As DWord, dwParam2 As DWord) Dim x As *Mp3Player x = dwInstance Select Case uMsg Case WOM_CLOSE Case WOM_DONE x->wh[1].dwUser = x->wh[1].dwUser - 1 If x->wh[0].dwUser = 0 Then x->read(hwo) Case WOM_OPEN End Select End Sub Public wh[2] As WAVEHDR Sub read(hwo As HWAVEOUT) Dim r As DWord If hwo = NULL Or wh[0].dwUser = 1 Or wh[1].dwUser > 1 Then Exit Sub waveOutUnprepareHeader(hwo, VarPtr(wh[switch]), SizeOf(WAVEHDR)) r = ReadMp3(buffer[switch], wfe.nAvgBytesPerSec) wh[switch].lpData = buffer[switch] wh[switch].dwBufferLength = r If r = 0 Then wh[0].dwUser = 1'これ以上再生しません waveOutPrepareHeader(hwo, VarPtr(wh[switch]), SizeOf(WAVEHDR)) waveOutWrite(hwo, VarPtr(wh[switch]), SizeOf(WAVEHDR)) wh[1].dwUser = wh[1].dwUser + 1 switch = switch + 1 If switch = 2 Then switch = 0 End Sub Function play(infile As *Byte) As Long If hwo <> NULL Then Exit Function If OpenMp3(infile) = FALSE Then Exit Function If GetMp3Header() = 0 Then CloseMp3() Exit Function End If buffer[0] = malloc(wfe.nAvgBytesPerSec) buffer[1] = malloc(wfe.nAvgBytesPerSec) waveOutOpen( VarPtr(hwo), WAVE_MAPPER, VarPtr(wfe), AddressOf(waveOutProc) ,VarPtr(this), CALLBACK_FUNCTION) read(hwo) Sleep(500) read(hwo) play = 1 End Function Sub stop() As Long If hwo = NULL Then Exit Sub wh[0].dwUser = 1 waveOutReset(hwo) While wh[1].dwUser > 0 Sleep(1) Wend waveOutUnprepareHeader(hwo, VarPtr(wh[0]), SizeOf(WAVEHDR)) waveOutUnprepareHeader(hwo, VarPtr(wh[0]), SizeOf(WAVEHDR)) free(buffer[0]) free(buffer[1]) waveOutClose(hwo) CloseMp3() hwo = NULL End Sub Function state(t As *DWord) As Long state = wh[1].dwUser If t = NULL Then Exit Function Dim mmt As MMTIME mmt.wType = TIME_SAMPLES waveOutGetPosition(hwo, VarPtr(mmt), SizeOf(MMTIME)) SetDWord(t,MulDiv(mmt.u , 1000, wfe.nSamplesPerSec)) End Function End Class #define SELFTEST #ifdef SELFTEST #N88BASIC Dim wp As Mp3Player Dim time As DWord Print "再生" wp.play("test.mp2") While wp.state(VarPtr(time)) Locate 4,1 Print time\1000;"sec" Sleep(1000) Wend wp.stop() Print "停止" #endif } ファイル名は好きに変えるようにして、 美しい音楽が聴こえてくるはずです。

表示オプション

横に並べて表示:
変化行の前後のみ表示: