CDの現在位置取得

ActiveBasicでのプログラミングでわからないこと、困ったことなどがあったら、ここで質問してみましょう(質問を行う場合は、過去ログやWeb上であらかじめ問題を整理するようにしましょう☆)。
返信する
メッセージ
作成者
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

CDの現在位置取得

#1 投稿記事 by yu0627 »

CDプレイヤーを今作っておりまして、一応完成したのですがなぜかCDの現在位置取得の部分で微妙にずれが起きます。
といいますのも、曲の最初の部分での現在位置の表示が1秒ではなくて2秒になっています。デバッグしてMCI_STATUS_PARMSのdwReturnをMCI_MSF_SECONDで変換して出力させても始めは1秒ではなくて2秒目からになってしまいます。
一応全ソースを載せておきます。長いですが。

コード: 全て選択

'-----------------------------------------------------------------------------
'  イベント プロシージャ
'-----------------------------------------------------------------------------
' このファイルには、ウィンドウ [MainWnd] に関するイベントをコーディングします。
' ウィンドウ ハンドル: hMainWnd

' TODO: この位置にグローバルな変数、構造体、定数、関数を定義します。

'グローバル変数宣言 ここから
	Const ID_TIMER = 100							'タイマーのID
	Dim mop As MCI_OPEN_PARMS						'MCI_OPEN_PARMS構造体
	Dim AllTrackNum As Long							'CDのトラック数
	Dim TrackNum As Long							'再生中のトラック番号
	Dim NowMusicMinute As Long						'再生中のトラックの長さ(分)
	Dim NowMusicSecond As Long						'再生中のトラックの長さ(秒)
	Dim BeforeMusicLong As QWord					'前まで再生した長さ
'ここまで

TrackNum=1


'CD用MCIデバイスをオープンする自作関数
Function OpenMciDevice() As Long
	Dim dwError As DWord							'
	Dim buffer[255] As Byte							'MCIエラーを格納する変数
	mop.dwCallback=hMainWnd							'
	mop.lpstrDeviceType="cdaudio"					'デバイスタイプを設定
	dwError=mciSendCommand(0, MCI_OPEN, 			'MCIデバイスを
		MCI_WAIT or MCI_OPEN_TYPE, mop)				'オープン
	If dwError Then									'
		mciGetErrorString(dwError, buffer, 255)		'MCIエラーを取得
		MessageBox(hMainWnd, Ex"デバイスのオープンに失敗\r\n" + buffer, "Error - LightCDPlayer", MB_OK or MB_ICONSTOP)
		'戻り値を設定
		OpenMciDevice=0
	Else
		OpenMciDevice=1
	End If
End Function


'MCIデバイスを閉じる自作関数
Sub CloseMciDevice()
	Dim dwDummy As DWord
	mciSendCommand(mop.wDeviceID, MCI_CLOSE, MCI_WAIT, dwDummy)
	mop.wDeviceID=0
End Sub


'トラック数を取得する自作関数
Sub GetTrackNum()
	Dim dwError As DWord
	Dim buffer[255] As Byte

	If mop.wDeviceID Then
		'再生中なら停止
		SendMessage(hMainWnd, WM_COMMAND, StopButton, 0)
	End If

	If OpenMciDevice()=0 Then Exit Sub

	'デバイスが準備未了かトレイが開いている時は終わる
	Dim msp As MCI_STATUS_PARMS
	msp.dwItem=MCI_STATUS_MODE
	dwError=mciSendCommand(mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, msp)

	If msp.dwReturn=MCI_MODE_NOT_READY Then
		CloseMciDevice()
		Exit Sub
	End If

	'トラック数を取得
	msp.dwItem=MCI_STATUS_NUMBER_OF_TRACKS
	dwError=mciSendCommand(mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, msp)
	If dwError Then
		'MCIデバイスを閉じる
		CloseMciDevice()
		Exit Sub
	End If

	AllTrackNum = msp.dwReturn

	'トラック情報を表示する
	TrackNum = 1
	GetTrackLong(TrackNum)
	wsprintf(buffer, "Track:01 - 0:00/%d:%02d", NowMusicMinute, NowMusicSecond)
	SetDlgItemText(hMainWnd, Static_TrackInfo, buffer)

	BeforeMusicLong = NowMusicMinute * 60 + NowMusicSecond

	'[PlayButton][NextmButton]を有効化する
	EnableWindow(GetDlgItem(hMainWnd, PlayButton), TRUE)
	EnableWindow(GetDlgItem(hMainWnd, NextmButton), TRUE)

	'MCIデバイスを閉じる
	CloseMciDevice()
End Sub


'CDトラックの長さを取得する自作関数
Sub GetTrackLong(TrackNum As Long)
	Dim msep As MCI_SET_PARMS
	Dim msp As MCI_STATUS_PARMS
	Dim sw As Long

	If mop.wDeviceID=0 Then
		'デバイスをオープン
		If OpenMciDevice()=0 Then Exit Sub
		sw = 1
	End If

	'時刻形式にMSFを指定
	msep.dwTimeFormat = MCI_FORMAT_MSF
	mciSendCommand(mop.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, msep)

	'TrackNumに格納されたトッラクの長さを取得
	msp.dwItem=MCI_STATUS_LENGTH
	msp.dwTrack=TrackNum
	mciSendCommand(mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM or MCI_TRACK, msp)

	'NowMusicMinuteとNowMusicSecondにトラックの長さを格納
	NowMusicMinute = MCI_MSF_MINUTE(msp.dwReturn)
	NowMusicSecond = MCI_MSF_SECOND(msp.dwReturn)

	If sw Then
		CloseMciDevice()
	End If
End Sub
'-----------------------------------------------------------------------------
' ウィンドウメッセージを処理するためのコールバック関数

Function MainWndProc(hWnd As DWord, dwMsg As DWord, wParam As DWord, lParam As DWord) As DWord
	' TODO: この位置にウィンドウメッセージを処理するためのコードを記述します。

	' イベントプロシージャの呼び出しを行います。
	MainWndProc=EventCall_MainWnd(hWnd,dwMsg,wParam,lParam)
End Function


'-----------------------------------------------------------------------------
' ここから下は、イベントプロシージャを記述するための領域になります。

Sub MainWnd_Destroy()
	If mop.wDeviceID Then
		SendMessage(hMainWnd, WM_COMMAND, StopButton, 0)
	End If
	lcdplyr_DestroyObjects()
	PostQuitMessage(0)
End Sub

Sub MainWnd_Create(ByRef CreateStruct As CREATESTRUCT)
	Dim buffer[255] As Byte
	
	'ボタンにアイコンを表示させる
	SendMessage(GetDlgItem(hMainWnd, BackmButton), BM_SETIMAGE, IMAGE_ICON, LoadIcon(CreateStruct.hInstance, IDI_ICON1))
	SendMessage(GetDlgItem(hMainWnd, PlayButton), BM_SETIMAGE, IMAGE_ICON, LoadIcon(CreateStruct.hInstance, IDI_ICON5))
	SendMessage(GetDlgItem(hMainWnd, PauseButton), BM_SETIMAGE, IMAGE_ICON, LoadIcon(CreateStruct.hInstance, IDI_ICON4))
	SendMessage(GetDlgItem(hMainWnd, StopButton), BM_SETIMAGE, IMAGE_ICON, LoadIcon(CreateStruct.hInstance, IDI_ICON6))
	SendMessage(GetDlgItem(hMainWnd, NextmButton), BM_SETIMAGE, IMAGE_ICON, LoadIcon(CreateStruct.hInstance, IDI_ICON3))
	SendMessage(GetDlgItem(hMainWnd, EjectButton), BM_SETIMAGE, IMAGE_ICON, LoadIcon(CreateStruct.hInstance, IDI_ICON2))

	'MainWndを画面の真ん中に移動
	Dim MainWndRect As RECT
	GetWindowRect(hMainWnd, MainWndRect)
	SetWindowPos(hMainWnd, 0,_
	(GetSystemMetrics(SM_CXSCREEN) - MainWndRect.right + MainWndRect.left) \ 2,_
    (GetSystemMetrics(SM_CYSCREEN) - MainWndRect.bottom + MainWndRect.top) \ 2,_
    0, 0, SWP_NOSIZE or SWP_NOZORDER)

	'トラック数を取得する
	GetTrackNum()
End Sub

Sub MainWnd_EjectButton_Click()
	If mop.wDeviceID Then
		'再生中のときは停止
		SendMessage(hMainWnd, WM_COMMAND, StopButton, 0)
	End If

	'MCIデバイスをオープン
	If OpenMciDevice()=0 Then Exit Sub

	'CDを取り出す
	mciSendCommand(mop.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, ByVal 0)

	'デバイスを閉じる
	CloseMciDevice()

	'再生・一時停止・停止・戻す・送るボタンを無効化する
	EnableWindow(GetDlgItem(hMainWnd, PlayButton), 0)
	EnableWindow(GetDlgItem(hMainWnd, PauseButton), 0)
	EnableWindow(GetDlgItem(hMainWnd, StopButton), 0)
	EnableWindow(GetDlgItem(hMainWnd, BackmButton), 0)
	EnableWindow(GetDlgItem(hMainWnd, NextmButton), 0)
End Sub

Sub MainWnd_ReLoadButton_Click()
	GetTrackNum()
End Sub

Sub MainWnd_PlayButton_Click()
	'変数宣言
	Dim MciError As DWord
	Dim buffer[255] As Byte
	Dim msep As MCI_SET_PARMS
	Dim msp As MCI_STATUS_PARMS
	Dim mpp As MCI_PLAY_PARMS
	Dim MciParms As DWord

	If mop.wDeviceID=0 Then
		'新しくMCIデバイスをオープンする
		If OpenMciDevice()=0 Then Exit Sub

		'演奏を開始
		'時刻形式にTMSFを指定
		msep.dwTimeFormat = MCI_FORMAT_TMSF
		mciSendCommand(mop.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, msep)

		mpp.dwCallback=hMainWnd
		mpp.dwFrom=MCI_MAKE_TMSF(TrackNum, 0, 0, 0)
		If TrackNum=AllTrackNum Then
			MciParms = MCI_FROM or MCI_NOTIFY
		Else
			mpp.dwTo=MCI_MAKE_TMSF(TrackNum, NowMusicMinute, NowMusicSecond, 0)
			MciParms=MCI_FROM or MCI_TO or MCI_NOTIFY
		End If
		MciError=mciSendCommand(mop.wDeviceID, MCI_PLAY, MciParms, mpp)
	Else
		'一時停止、シーク時からの復帰の時
		'再生
		mpp.dwCallback=hMainWnd
		If TrackNum=AllTrackNum Then
			MciParms=MCI_NOTIFY
		Else
			mpp.dwTo=MCI_MAKE_TMSF(TrackNum + 1, NowMusicMinute, NowMusicSecond, 0)
			MciParms=MCI_TO or MCI_NOTIFY
		End If
		MciError=mciSendCommand(mop.wDeviceID, MCI_PLAY, MciParms, mpp)
	End If

	If MciError Then
		'再生時にエラーが起きた時
		mciGetErrorString(MciError, buffer, 255)
		MessageBox(hMainWnd, Ex"再生に失敗。\r\n" + buffer, "Error - LightCDPlayer", MB_OK or MB_ICONSTOP)

		'MCIデバイスを閉じる
		CloseMciDevice()
		Exit Sub
	End If

	'再生ボタンを無効化し、一時停止・停止ボタンを有効化する
	EnableWindow(GetDlgItem(hMainWnd, PlayButton), 0)
	EnableWindow(GetDlgItem(hMainWnd, PauseButton), 1)
	EnableWindow(GetDlgItem(hMainWnd, StopButton), 1)

	'タイマー処理を開始する
	SetTimer(hMainWnd, ID_TIMER, 100, 0)
End Sub

Sub MainWnd_PauseButton_Click()
	Dim buffer[255] As Byte
	
	'一時停止
	mciSendCommand(mop.wDeviceID, MCI_PAUSE, 0, ByVal 0)

	'再生・停止ボタンを有効化し、一時停止ボタンを無効化する
	EnableWindow(GetDlgItem(hMainWnd, PlayButton), 1)
	EnableWindow(GetDlgItem(hMainWnd, PauseButton), 0)
	EnableWindow(GetDlgItem(hMainWnd, StopButton), 1)
	
	'タイマー処理を終了する
	KillTimer(hMainWnd, ID_TIMER)
End Sub

Sub MainWnd_StopButton_Click()
	Dim MciErr As Long
	Dim dwCallBack As DWord
	Dim buffer[255] As Byte

	'停止
	MciErr=mciSendCommand(mop.wDeviceID, MCI_STOP, MCI_WAIT, dwCallBack)
	If MciErr Then
		MessageBox(hMainWnd, "音楽の停止に失敗", "Error - LightCDPlayer", MB_OK or MB_ICONSTOP)
		ExitSub
	End If

	'デバイスを閉じる
	CloseMciDevice()

	'再生ボタンを有効化し、一時停止・停止ボタンを無効化する
	EnableWindow(GetDlgItem(hMainWnd, PlayButton), 1)
	EnableWindow(GetDlgItem(hMainWnd, PauseButton), 0)
	EnableWindow(GetDlgItem(hMainWnd, StopButton), 0)

	'トラック情報を更新する
	GetTrackLong(TrackNum)
	wsprintf(buffer, "Track:%02d - 0:00/%d:%02d", TrackNum, NowMusicMinute, NowMusicSecond)
	SetDlgItemText(hMainWnd, Static_TrackInfo, buffer)

	'タイマー処理を終了する
	KillTimer(hMainWnd, ID_TIMER)
End Sub

Sub MainWnd_NextmButton_Click()
	Dim buffer[255] As Byte, dwCallBack As DWord
	
	If TrackNum<>AllTrackNum Then
		TrackNum=TrackNum + 1
		If TrackNum=AllTrackNum Then
			EnableWindow(GetDlgItem(hMainWnd, NextmButton), 0)
		End If
		EnableWindow(GetDlgItem(hMainWnd, BackmButton), 1)
	ElseIf TrackNum=AllTrackNum Then
		Exit Sub
	End If

	'トラック情報を表示
	GetTrackLong(TrackNum)
	BeforeMusicLong = BeforeMusicLong + ((NowMusicMinute * 60) + NowMusicSecond)
	wsprintf(buffer, "Track:%02d - 0:00/%d:%02d", TrackNum, NowMusicMinute, NowMusicSecond)
	SetDlgItemText(hMainWnd, Static_TrackInfo, buffer)

	If mop.wDeviceID Then
		'再生中のとき
		mciSendCommand(mop.wDeviceID, MCI_STOP, MCI_WAIT, dwCallBack)
		CloseMciDevice()
		SendMessage(hMainWnd, WM_COMMAND, PlayButton, 0)
	End If
End Sub

Sub MainWnd_BackmButton_Click()
	Dim buffer[255] As Byte, dwCallBack As DWord

	If TrackNum<>1 Then
		TrackNum=TrackNum - 1
		If TrackNum=1 Then
			EnableWindow(GetDlgItem(hMainWnd, BackmButton), 0)
		End If
		EnableWindow(GetDlgItem(hMainWnd, NextmButton), 1)
	ElseIf TrackNum=AllTrackNum Then
		Exit Sub
	End If

	BeforeMusicLong = BeforeMusicLong - ((NowMusicMinute * 60) + NowMusicSecond)

	'トラック情報を表示
	GetTrackLong(TrackNum)
	wsprintf(buffer, "Track:%02d - 0:00/%d:%02d", TrackNum, NowMusicMinute, NowMusicSecond)
	SetDlgItemText(hMainWnd, Static_TrackInfo, buffer)

	If mop.wDeviceID Then
		'再生中のとき
		mciSendCommand(mop.wDeviceID, MCI_STOP, MCI_WAIT, dwCallBack)
		CloseMciDevice()
		SendMessage(hMainWnd, WM_COMMAND, PlayButton, 0)
	End If
End Sub

Sub MainWnd_MciNotify(flags As Long, DevID As DWord)
	If flags=MCI_NOTIFY_SUCCESSFUL Then
		If TrackNum<>AllTrackNum Then
			Dim dwCallBack As DWord
			TrackNum=TrackNum + 1
			If TrackNum=AllTrackNum Then
				EnableWindow(GetDlgItem(hMainWnd, NextmButton), 0)
			End If
			EnableWindow(GetDlgItem(hMainWnd, BackmButton), 1)
			mciSendCommand(mop.wDeviceID, MCI_STOP, MCI_WAIT, dwCallBack)
			CloseMciDevice()
			GetTrackLong(TrackNum)
			BeforeMusicLong = BeforeMusicLong + ((NowMusicMinute * 60) + NowMusicSecond)
			SendMessage(hMainWnd, WM_COMMAND, PlayButton, 0)
		Else TrackNum=AllTrackNum Then
			SendMessage(hMainWnd, WM_COMMAND, StopButton, 0)
		End If
	End If
End Sub

Sub MainWnd_VersionButton_Click()
	DialogBox(hMainWnd, "VerDlg")
End Sub

Sub MainWnd_QueryClose(ByRef cancel As Integer)
	If mop.wDeviceID and IsWindowEnabled(GetDlgItem(hMainWnd, PlayButton))=FALSE Then
		'もし再生中なら確認メッセージをだす。
		'ユーザーが「いいえ」を選んだらcancel変数に1を格納し終了させない
		If MessageBox(hMainWnd, "再生中です。終了しますか?", "LigthCDPlayer", MB_YESNO or MB_ICONQUESTION)=IDNO Then
			cancel=1
		End If
	End If
End Sub
Sub MainWnd_Timer(TimerID As DWord)
	If TimerID=ID_TIMER Then
		Dim msep As MCI_SET_PARMS				'MCI_SET_PARMS構造体
		Dim msp As MCI_STATUS_PARMS				'MCI_STATUS_PARMS構造体
		Dim buffer[255] As Byte					'文字列格納用
		Dim MusicMinute As Long					'CDで現在再生している位置(分)
		Dim MusicSecond As Long					'CDで現在再生している位置(秒)
		Dim temp As DWord						'数字一時格納用
		Dim ReturnMinute As Long				'現在位置取得の戻り値(分)
		Dim ReturnSecond As Long				'現在位置取得の戻り値(秒)
		'時刻形式にMSFを設定
		msep.dwTimeFormat = MCI_FORMAT_MSF
		mciSendCommand(mop.wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT, msep)

		'再生中のトラックの現在位置を取得
		msp.dwItem=MCI_STATUS_POSITION
		mciSendCommand(mop.wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, msp)

		ReturnMinute=MCI_MSF_MINUTE(msp.dwReturn)
		ReturnSecond=MCI_MSF_SECOND(msp.dwReturn)

		'現在位置を計算する
		If TrackNum<>1 Then
			temp = NowMusicMinute * 60 + NowMusicSecond - (BeforeMusicLong -  (ReturnMinute * 60 + ReturnSecond))
			If temp >= 60 Then
				MusicMinute = temp \ 60
				MusicSecond = temp - (MusicMinute * 60)
			Else
				MusicMinute = 0
				MusicSecond = temp
			End If
		Else
			MusicMinute=ReturnMinute
			MusicSecond=ReturnSecond
		End If

		'トラック情報を更新する
		wsprintf(buffer, "Track:%02d - %d:%02d/%d:%02d", TrackNum, MusicMinute, MusicSecond, NowMusicMinute, NowMusicSecond)
		SetDlgItemText(hMainWnd, Static_TrackInfo, buffer)
	End If
End Sub
仕様でしたらすみません。お答えお願いいたします。
淡幻星
記事: 183
登録日時: 2005年7月19日(火) 07:02
お住まい: 宮城県
連絡する:

役に立つかわかりませんが・・・

#2 投稿記事 by 淡幻星 »

焼き方(ROMならば製作仕様)にも寄りますが、
一般に、トラック間には2秒の空白があります(たしか)。
それが反映されているのではないかと、素人の立場から邪推してみますが、
いかがでしょうか?
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

返信@yu0627

#3 投稿記事 by yu0627 »

返信してくださりありがとうございます。
> 焼き方(ROMならば製作仕様)にも寄りますが、
> 一般に、トラック間には2秒の空白があります(たしか)。
> それが反映されているのではないかと、素人の立場から邪推してみますが、
> いかがでしょうか?
WindowsMediaPlayerで書き込んだものと既製品どちらも試してみましたが、どちらも2秒多くなっています。やはりそうなのでしょうか...。
とりやえず2秒分を少なくしてみました。しかし、それではトラック数が大きくなるにつれて0秒以上になり、また、2*トラック数にするとその後のトッラクの表示がおかしくなります。
前に時刻形式をTMSFにしてトラックを指定してやってみましたがそれも×でした...。
Oryaaaaa
記事: 24
登録日時: 2005年6月02日(木) 00:12
お住まい: 愛知県岡崎市
連絡する:

#4 投稿記事 by Oryaaaaa »

ソースを見てないので申し訳ないけど・・・

音楽CDは一番最初が2秒、あとは2秒だったり・0秒だったり・いろいろ
です。EACというCDのリップを使うとそれがよく分かります。まず、
テストしている音楽CDの曲間スペースが一定か変動型か確認したほうが
いいでしょう。

EACのサイト
http://www.exactaudiocopy.de/
yu0627
記事: 154
登録日時: 2005年5月31日(火) 14:53

返信@yu0627

#5 投稿記事 by yu0627 »

> ソースを見てないので申し訳ないけど・・・
>
> 音楽CDは一番最初が2秒、あとは2秒だったり・0秒だったり・いろいろ
> です。EACというCDのリップを使うとそれがよく分かります。まず、
> テストしている音楽CDの曲間スペースが一定か変動型か確認したほうが
> いいでしょう。
>
> EACのサイト
> http://www.exactaudiocopy.de/
EACの曲間って「ギャップ」のことでしょうか。もしそうなら、その欄を見ると「不明」になっています。
ギャップの検出方法を変えても同じ結果です。
返信する