ab.com コミュニティ

ActiveBasicを通したコミュニケーション
現在時刻 - 2018年10月23日(火) 00:21

All times are UTC+09:00




新しいトピックを投稿する  トピックへ返信する  [ 8 件の記事 ] 
作成者 メッセージ
投稿記事Posted: 2008年9月06日(土) 05:29 
N88モードにてMP3ファイルの再生方法をご教授いただけないでしょうか?

WAVファイルについては「Win32プログラミング講座 ~ Step29. WAVEファイルを再生する ~」
にて記述されておりますが、WAVだとサイズも大きいのでMP3を扱いたいのです。
次の項「Win32プログラミング講座 ~ Step30. MCIコマンドで音楽ファイルを再生する ~」
にてMP3ファイルの取り扱いについて触れていますが、N88モードにてどのように扱ったらよいのかが分かりません。

希望としては、以下のように使いたいと考えております

・非同期にてファイルを指定すると再生する
・現在再生しているMP3の再生を終了する

例えば以下の様に使用できればと思います。

Playmp3Stop("C:\Winnt\Media\The Microsoft Sound.wav") '再生
'何か別の処理をする
Playmp3Sound() '現在再生しているMP3の再生を終了

宜しくお願いいたします。


通報する
ページトップ
   
 記事の件名: 自己レスです
投稿記事Posted: 2008年9月07日(日) 08:06 
「Win32プログラミング講座 ~ Step30. MCIコマンドで音楽ファイルを再生する ~」
のサンプルコードをN88BASICモードとして以下の様に置き換えてみました。
試行錯誤にて、「どうにか、動作出来るレベル」になった程度なので、本来の手法(?)とは違うのだろうなぁと感じています。

「ここはこうすべき」、「この方が効率的」、「ここが変」
などなど、アドバイスをいただけますと幸いです。

よろしくお願いいたします。



#N88BASIC
#include <api_mmsys.sbp>
Dim I$ AS STRING
Dim filename(500) AS BYTE

' ----------------------------------ここから----------------------------------

Dim mop As MCI_OPEN_PARMS
*loop
Openfile()
Playsound()
I$=Input$(1)
Playstop()
goto *loop
end
' ----------------------------------ここまで----------------------------------
'↑先頭部分には、MCIデバイスのオープン情報のための構造体を用意します。

Sub Openfile()
Dim ofn As OPENFILENAME
Dim buffer[MAX_PATH-1] As Byte

'ファイル名を取得
ofn.lStructSize=76
ofn.hwndOwner=_PromptSys_hWnd'hMainWnd
ofn.lpstrFilter=Ex"音楽 ファイル(*.wav;*.mid;*.mp3)\0*.wav;*.mid;*.mp3\0すべてのファイル(*.*)\0*\0\0"
ofn.nFilterIndex=1
ofn.nMaxFile=MAX_PATH
ofn.lpstrFile=buffer
GetOpenFileName(ofn)
lstrcpy(filename,buffer)
End Sub
'↑OPENボタンがクリックされたときに呼び出されるイベントです。GetOpenFileName関数でファイル名を取得し、テキストボックス(Static_Path)にファイルパスを表示します。


Sub Playsound()
Dim bErr As Long
Dim mpp As MCI_PLAY_PARMS
Dim buffer[MAX_PATH-1] As Byte

'再生中の場合は停止させる
If mop.wDeviceID Then Playstop()

'サウンド ファイルのパスを設定します。
mop.lpstrElementName=buffer
'メッセージ通知のためのウィンドウを指定
mop.lpstrElementName=filename
mop.dwCallback=_PromptSys_hWnd

'MCIデバイスをオープン
bErr=mciSendCommand(0,MCI_OPEN,MCI_OPEN_ELEMENT,mop)
If bErr Then
MessageBox(_PromptSys_hWnd,"デバイスのオープンに失敗","error",MB_OK)
Exit Sub
End If

'再生
mpp.dwCallback=_PromptSys_hWnd
bErr=mciSendCommand(mop.wDeviceID,MCI_PLAY,MCI_NOTIFY,mpp)
If bErr Then
MessageBox(_PromptSys_hWnd,"デバイスの再生に失敗","error",MB_OK)
Exit Sub
End If
End Sub
'↑PLAYボタンがクリックされたときに呼び出されるイベントです。MCI_OPENコマンドでMCIデバイスを開き、MCI_PLAYコマンドでデバイスを再生します。


Sub Playstop()
Dim bErr As Long
Dim dwCallback As DWord

'停止
bErr=mciSendCommand(mop.wDeviceID,MCI_STOP,MCI_WAIT,dwCallback)
If bErr Then
MessageBox(_PromptSys_hWnd,"デバイスの停止に失敗","error",MB_OK)
Exit Sub
End If

'デバイスを閉じる
mciSendCommand(mop.wDeviceID,MCI_CLOSE,MCI_WAIT,dwCallback)

mop.wDeviceID=0
End Sub
'↑STOPボタンがクリックされたときに呼び出されるイベントです。MCI_STOPコマンドでデバイスを停止させ、MCI_CLOSEコマンドでデバイスをクローズしています。


Sub MainWnd_MciNotify(flags As Long, DevID As Long)
Dim dwCallback As DWord

If flags=MCI_NOTIFY_SUCCESSFUL Then
'デバイスを閉じる
mciSendCommand(DevID,MCI_CLOSE,MCI_WAIT,dwCallback)

mop.wDeviceID=0
MessageBox(_PromptSys_hWnd,"再生終了","Sound test",MB_OK)
End If
End Sub
/*
↑MciNotifyは、再生が終了した場合などにMCIコマンドから送られるイベントです。RADツールの「イベント処理」ダイアログのMMSYSタブで表示されています。
再生が正常に終了した場合(flagsパラメータに MCI_NOTIFY_SUCCESSFUL フラグがセットされていたとき)はMCI_CLOSEコマンドを送り、MCIデバイスをクローズします。DevID変数とmop.wDeviceID変数には同じ値がセットされています。


通報する
ページトップ
   
 記事の件名: ループ再生について
投稿記事Posted: 2008年9月08日(月) 22:49 
上記にて再生は出来たと書きましたが、「MCI_NOTIFY」の取り扱いが理解出来ず、ループ再生 (BGMのように扱いたい) の方法が分かりません。

検討違いの質問かもしれませんが、ご教授の程宜しくお願いいたします。


通報する
ページトップ
   
投稿記事Posted: 2008年9月09日(火) 01:30 
オフライン

登録日時: 2005年5月31日(火) 10:52
記事: 264
住所: 高知
引用:
> 上記にて再生は出来たと書きましたが、「MCI_NOTIFY」の取り扱いが理解出来ず、ループ再生 (BGMのように扱いたい) の方法が分かりません。
>
> 検討違いの質問かもしれませんが、ご教授の程宜しくお願いいたします。

トモカズさんがされようとしていることはAB3.X以降のN88BASICモードでの
実装は正攻法では無理だと思います。

勿論、正攻法でできないだけでN88BASIC互換モードの裏側を理解している者に
とってはそんなに難しいことではありませんので少し時間を頂ければ
ループ再生のサンプルをのせたいと思います。


通報する
ページトップ
 記事の件名:
投稿記事Posted: 2008年9月09日(火) 05:38 
オフライン

登録日時: 2005年5月31日(火) 10:52
記事: 264
住所: 高知
ということでサンプルできましたのでのせときます。

[hide=ソースはこちら]
コード:
#N88BASIC
#include <api_mmsys.sbp>

'----------------オマジナイ-----------------
Dim proc As DWord
proc = SetWindowLong(_PromptSys_hWnd,GWL_WNDPROC,AddressOf(MyCallback))
'-------------------------------------------

'ウィンドウメッセージ
Const WM_MCIOPEN = WM_USER + 1
Const WM_MCICLOSE = WM_USER + 2
Const WM_MCIPLAY = WM_USER + 3
Const WM_MCISTOP = WM_USER + 4

'構造体の準備
Dim mop As MCI_OPEN_PARMS
Dim mpp As MCI_PLAY_PARMS


'MCIデバイスを開く
Dim device1 As Long
device1 = SendMessage(_PromptSys_hWnd,WM_MCIOPEN,"waveaudio","C:\WINDOWS\Media\Windows XP Startup.wav")
Dim device2 As Long
device2 = SendMessage(_PromptSys_hWnd,WM_MCIOPEN,"waveaudio","C:\WINDOWS\Media\notify.wav")

'device1をループ再生
SendMessage(_PromptSys_hWnd,WM_MCIPLAY,device1,MCI_NOTIFY)

'device2を1秒おきに10回再生
Dim cnt As Long
For cnt = 1 To 10
	SendMessage(_PromptSys_hWnd,WM_MCIPLAY,device2,0)
	Sleep(1000) 
Next

'MCIデバイスを閉じる
SendMessage(_PromptSys_hWnd,WM_MCICLOSE,device1,0)
device1 = 0
SendMessage(_PromptSys_hWnd,WM_MCICLOSE,device2,0)
device2 = 0

End

'--------------------コールバック関数---------------------------------------------------
Function MyCallback(hWnd As HWND, Msg As DWord, wParam As WPARAM, lParam As LPARAM) As LRESULT
	Select Case Msg
		Case WM_DESTROY '必ず実装してください。
			'プログラムの終了時に開いたままのデバイスを必ずここで全て閉じること!
			'複数のBGMやサウンドを再生する場合はdeviceを配列にしてくといいかも。
			If device1 <> 0 Then mciSendCommand(device1,MCI_CLOSE,MCI_WAIT,hWnd)
			If device2 <> 0 Then mciSendCommand(device2,MCI_CLOSE,MCI_WAIT,hWnd)

		Case WM_MCIOPEN 'デバイスを開く処理
			mop.lpstrDeviceType = wParam
			mop.lpstrElementName = lParam
			mop.dwCallback = _PromptSys_hWnd
			mciSendCommand(NULL,MCI_OPEN,MCI_OPEN_TYPE or MCI_OPEN_ELEMENT,mop)
			MyCallback = mop.wDeviceID
			Exit Function

		Case WM_MCICLOSE 'MCIデバイスを閉じる処理
			mciSendCommand(wParam,MCI_CLOSE,MCI_WAIT,hWnd)
			MyCallback = 0
			Exit Function

		Case WM_MCIPLAY 'MCIデバイスを再生する処理
			mpp.dwCallback = hWnd
			mpp.dwFrom = 0
			mciSendCommand(wParam,MCI_PLAY,lParam or MCI_FROM,mpp)
			MyCallback = 0
			Exit Function

		Case WM_MCISTOP 'MCIデバイスを停止する処理
			mciSendCommand(wParam,MCI_STOP,MCI_WAIT,hWnd)
			MyCallback = 0
			Exit Function			

		Case MM_MCINOTIFY 'MCI_NOTIFYの処理
			Select Case wParam
				Case MCI_NOTIFY_SUCCESSFUL
					mpp.dwCallback = hWnd
					mpp.dwFrom = 0
					'MCIデバイスの再生(notifyを指定しているのでループ再生になる)
					mciSendCommand(wParam,MCI_PLAY,MCI_FROM or MCI_NOTIFY,mpp)
			End Select
	End Select
		MyCallback = CallWindowProc(proc,hWnd,Msg,wParam,lParam)
End Function
[/hide]


肝心のMP3の再生ですが、"waveaudio"の部分を"mpegvideo"にすれば再生できるはずです。
内容的に難しくなってしまったので分からないことがあれば質問してください。


通報する
ページトップ
投稿記事Posted: 2008年9月12日(金) 09:53 
NoWestさん、早々にサンプログラムまで作成していただき、ありがとうございます。

N88モードでは、そもそも正攻法では出来なかったのですね。
さて、サンプルプログラムを色々と自分なりに(使い方を)理解しようと
試してみました。

サンプルをベースに簡易的に、手を入れて自分なりのサンプルを色々作成してみました。(Device1を途中で止める・・・だとか、ここでDvice2を再生するだとか・・・試してみました)
とりあえず、扱い方は理解したので(と思います)、自分のソフトに実装してみました。

「思った通りの動作をした」・・・と思いきや、暫く実行していると、強制終了してしまいました。
その後も、MICデバイスを開くタイミングだとかMICデバイスを閉じるタイミングなど変更して試しています。

それでも、未だに正常に動作しないのですが、(Device1がループ再生しているかと思いきや4~5回再生すると終了してしまったり・・・)
私の実装方法に問題があると思いますので、もうちょっと頑張ってみます。
(自作簡易サンプルだとうまく動作するのに、それと同様に組み込んでるんですけどね・・)


通報する
ページトップ
   
投稿記事Posted: 2008年9月15日(月) 16:39 
オフライン

登録日時: 2005年5月31日(火) 10:52
記事: 264
住所: 高知
引用:
> N88モードでは、そもそも正攻法では出来なかったのですね。
> さて、サンプルプログラムを色々と自分なりに(使い方を)理解しようと
> 試してみました。
AB2.Xの頃はMCISound命令というのが実装されていまして
こいつを使ってMCIを操作していたんですが、AB3.X系からは実装されていません。

引用:
> 「思った通りの動作をした」・・・と思いきや、暫く実行していると、強制終了してしまいました。
> その後も、MICデバイスを開くタイミングだとかMICデバイスを閉じるタイミングなど変更して試しています。
>
> それでも、未だに正常に動作しないのですが、(Device1がループ再生しているかと思いきや4~5回再生すると終了してしまったり・・・)
> 私の実装方法に問題があると思いますので、もうちょっと頑張ってみます。
> (自作簡易サンプルだとうまく動作するのに、それと同様に組み込んでるんですけどね・・)
何が問題なのかもう少し具体的な情報がないと判断できません。

OSは?
ABのバージョンは?
プログラムの流れは?

何が問題なのか整理をつけながらデバックするとよいでしょう。
私が良く使う手はプログラムの同一機能の部分を「'」コメントアウトして
プログラムの全体に問題点がないかを探しておき、
今度は細かな部分を徐々に確認していきます。

今回のサンプルで言えば、
1.まずはMCIに関するAPI関連部分を全てコメントアウトして
MCIの再生部分以外に問題がないことを確認します。

2.続いてMCIデバイスを開く部分と閉じる部分のコメントアウトを外し
確実に開かれたデバイスが閉じられているかを確認します。

3.最後にその他の機能を少しずつ回復させながらデバックを行います。

全体を通していえますが、コメントアウトを外しながらその部分を記述を
確認しましょう。引数を間違えるとか大ポカをやらかしていることも多々あります。

あとはGetLastError関数とmciGetErrorString関数を使うのも手ですね。
コイツを使うとエラーの詳細情報を得られます。


通報する
ページトップ
 記事の件名: 約1年半が経過
投稿記事Posted: 2010年4月25日(日) 07:26 
NoWestさん、ありがとうございました。
約1年半が経過してしまいましたが、ようやく解決いたしました。
全然、分からなくって半ば諦めかけていました。

> 「思った通りの動作をした」・・・と思いきや、暫く実行していると、強制終了してしまいました。

MP3のループ再生のプログラムを実装すると、確かにこのような症状になるのですが、
原因は (なのかどうかは、定かではありませんが・・・) 文字列変数(String)を多用していたからだったのかもしれません。
これを修正したら、強制終了が起こる事は一切無くなりました。
String多用であっても、MP3再生をしなければ強制終了が起こらないというのも謎です。

文字列変数を使うと不安定になるのでしょうか?


通報する
ページトップ
   
期間内表示:  ソート  
新しいトピックを投稿する  トピックへ返信する  [ 8 件の記事 ] 

All times are UTC+09:00


オンラインデータ

このフォーラムを閲覧中のユーザー: なし & ゲスト[1人]


トピック投稿:  可
返信投稿:  可
記事編集: 不可
記事削除: 不可
ファイル添付: 不可

検索:
ページ移動:  
cron
Powered by phpBB® Forum Software © phpBB Limited
Japanese translation principally by KONISHI Yohsuke