mcrblog

vcpp-ml

2000年02月

29

[vcpp 00038469] Re: 低レベルオーディオの使い方

安葉と申します.

(注)本文ちょっと長いかもしれません.

> 注: WaveProcコールバック関数で実装しています

> ・MM_WOM_OPEN中でwaveOutPause,waveOutPrepareHeaderなどを
>  呼び出すと、内部で落ちてしまう
> ・MM_WOM_DONE中でwaveOutCloseを呼び出すと、次の行に
>  制御が戻ることなくデバイスが閉じられてしまう。

これは, Windows から呼び出されるコールバック関数
内に実装していると言う事でしょうか ?

私の記憶では, 加藤歓隆さんは, だいぶ前に「低レベル
オーディオコールバック関数内では低レベルオーディオ
関数を呼ばない事」との指摘を多数の方から受けていた
ような気がしますが...

[vcpp 00035464] 低レベルオーディオなどで
辺りで...( ちょっと探してしまいました(笑) )

まぁ, それはおいといて,

> ・DLLで実装し、それ自身はWindowを持たない(現在)
> ・再生開始の指示が出されると、デバイスのオープン、
>  データブロックが終わるまでの追加、デバイスのクローズを
>  非同期で行う←呼び出し側スレッドと

> WaveProcコールバック実装するのは無理があるのでしょうか?
> 知恵を貸して下さい。

以下コールバック関数内では低レベルオーディオ処理
を行わない! という前提の下に書きます.

以下のような作りにしたらどうでしょうか ?
ちょっと複雑になるので, 言葉だけで説明するのはめ
ちゃくちゃ辛いのですけれども.

まず, WaveOutOpen しますね.
その後, デバイス監視用としてメッセージ処理をする
ループを含んだスレッドを起こします.
このスレッドを Thread1 とします.

当然 WaveOutWrite をコールする前にバッファの確保
などの準備は全て完了させておいてください.
waveOutPrepareHeader をしておくと言う事です.

以下 Windows からのコールバック関数を waveOutProc
と書きます.
waveOutWrite をコールし, 再生が終わると, waveOutProc
が WOM_DONE を引数に呼ばれますね.
そしたら, Thread1 に向かって再生が終了したよ! と
言う旨の通知メッセージを PostThreadMessage で投
げます.

Thread1 は waveOutWrite とは別のスレッドですから
こちら側では何を行っても大丈夫です.
但し, 速めに処理を切り上げないとフレーム落ちするの
は一緒ですが.
で, Thread1 内でバッファにデータを書き込んで, 再び
Prepare し, Write する...と.

コールバック関数を用いる方法では, たぶんこれが基本
的なアルゴリズムになると思います.

ちなみに, waveOutProc の第4引数に Prepare で渡し
た WAVEHDR 構造体へのポインタがわたってくるのはご
存知ですよね ?
更に, WAVEHDR 構造体のメンバ dwUser メンバは好き
勝手に使ってよい事もご存知ですよね ?

これらを上手に使えばコールバック方式での低レベル
オーディオ操作が矛盾無く行えると思います.

# 私はこの方法で, ちゃんと再生デバイスが動作してい
# ますよ( WindowsNT + SP5, VC++6.0 SP 無し ).

### なお, コールバック関数内で低レベルオーディオ関
### 数等をコールしている場合はこの方法でも上手に動
### 作する保証はありません.


では, がんばってください.
参考になれば幸いです.



----------
Koichi YASUBA
y...@ntt-it.co.jp
29

[vcpp 00038468] Re: 低レベルオーディオの使い方


すずきです。

ちょうど、WaveOut系のclassを作ってたところなので…。


On Tue, 29 Feb 2000 19:12:04 +0900
Kato Kanryu <k...@aurora.dti.ne.jp> wrote:
 
> WaveProcコールバック実装するのは無理があるのでしょうか?
> 知恵を貸して下さい。
 コールバック関数内では、::EnterCriticalSectionなど極一部の
 APIしか使えません。(詳しくはHELPを見て下さい)


 で、自分はこんな感じで実装しました、メールだと全部載せるには
 長いので大事なところだけですが、参考までに。

WAVEFORMATEX    f_format;
HWAVEOUT        f_waveout;

// セマフォ。
// ::waveOutOpenする前に作ってインスタンスデータとして渡す
HANDLE          f_gatekeeper; // = ::CreateSemaphore(NULL, 2, 2, NULL);

// waveOutWrite用の書き込みバッファ。
// 2つまで同時に::waveOutWrite出来るので、3つで回す。 
WAVEHDR        *f_wave_headers[3];
unsigned int    f_buff_pos;   // = 0;

unsigned long   f_block_size; // バッファのサイズ



static void CALLBACK waveout::wave_proc(HWAVEOUT hWave,
                                        UINT     uMsg,
                                        DWORD    dwUser,
                                        DWORD    dw1,
                                        DWORD    dw2)
{
  if (uMsg == WOM_DONE) {
    ::waveOutUnprepareHeader(hWave,
                             (WAVEHDR *)dw1,
                             sizeof(WAVEHDR));

    //::waveOutOpenの時にインスタンスデータとして
    // セマフォのハンドルを渡してます
    ::ReleaseSemaphore((HANDLE)dwUser, 1, NULL);
  }
}

unsigned long waveout::write(void *samples, unsigned long num_bytes)
{
  unsigned long size;
  
  size = f_block_size < size? f_block_size: num_bytes;
  if (size == 0)
    return 0;
  
  ::CopyMemory(f_wave_headers[f_buff_pos]->lpData, samples, size);
  f_wave_headers[f_buff_pos]->dwBufferLength = size;
  ::waveOutPrepareHeader(f_waveout,
                         f_wave_headers[f_buff_pos],
                         sizeof(WAVEHDR));

  if (::WaitForSingleObject(f_gatekeeper, 3000) == WAIT_TIMEOUT)
    return 0;

  ::waveOutWrite(f_waveout, f_wave_headers[f_buff_pos], sizeof(WAVEHDR));

  if (++f_buff_pos > 2)
    f_buff_pos = 0;
  
  return size;
}


セマフォを使って一度にデバイスに書き込む回数を2回に制限して、
あとは、WAVEデータをよみこんで、writeで書き込んでいくだけです。
# 一度に全部書いてもいいし、分割して書いてもOK。

# こんな感じ
# while (size = ::fread(samples, 1, 11025, fd))
#   pWaveout->write(samples, size);
#

ではでは。
 

                                                                    ▽ 
                                    T.Suzuki / s...@ga2.so-net.ne.jp 
 ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄
29

[vcpp 00038467] Re: #define BUFFER_SIZE 1024 は最悪?

村田です。

> 樋口@raidwayです。
>
> On Tue, 29 Feb 2000 01:31:39 +0900
> "Takuya Murata" <s...@bu.iij4u.or.jp> wrote:
>
> >MAX_PATHの実装を見てみると、256となっています。これだと長いファイル名

> >深いパスがつくとすぐに256では足りなくなると思います。
>
> MAX_PATHの意味する所は、例えば256だったら「ディレクトリ名が200
> バイトだった場合はファイル名として使えるのは56-1('\'の分)バイト」
> という事です(これはWin32に限らず、Linuxのext2fsでも*BSDのufsでも
> 同じだったような。うろ覚えですが)。

そうなんですか。

> 実際にNT4SP6aのコマンドプロンプトからひたすらmkdirして実験して
> みると、FAT16でもNTFSでも確かに260バイトまでのパス名を作成する
> 事はできます。
>
> が、Explorerで枝の一番下のファイルを削除しようとすると「パスが
> 長すぎまっせ」と怒られて削除できません(MAX_PATH = 256と思いこん
> でるのかもしれません)。なので、こういう意味では確かにMAX_PATHは
> あまりあてにならないかもしれませんね。

出来るだけ動的に確保するのがやはり安全というわけですね。

---
村田 拓哉 (MURATA Takuya)
t...@ff.iij4u.or.jp
http://www.ff.iij4u.or.jp/~takusi/
29

[vcpp 00038466] 低レベルオーディオの使い方

加藤歓隆です。

低レベルオーディオを用いて、音声再生への
細かいアプローチに対応させようとしているところなのですが、
NT4.0でも動作させようとしたところ、
いくつかの問題が発生しました。

注: WaveProcコールバック関数で実装しています

・MM_WOM_OPEN中でwaveOutPause,waveOutPrepareHeaderなどを
 呼び出すと、内部で落ちてしまう
・MM_WOM_DONE中でwaveOutCloseを呼び出すと、次の行に
 制御が戻ることなくデバイスが閉じられてしまう。

僕は、以下のような動作をさせたいと思っています。

・DLLで実装し、それ自身はWindowを持たない(現在)
・再生開始の指示が出されると、デバイスのオープン、
 データブロックが終わるまでの追加、デバイスのクローズを
 非同期で行う←呼び出し側スレッドと

WaveProcコールバック実装するのは無理があるのでしょうか?
知恵を貸して下さい。
29

[vcpp 00038465] Re: [vcpp 00038464] Re: SDIアプリケーションでプログレスバーを表示するには

どうも坂本@エーディーです

いつも大変お世話になっております。


> > 実はCProgressCtrl::Createを使いたいのですが
> > どうもこの関数、プログレスバーのIDが必要みたいなのです。
>
> CWnd::CreateEx でも必要ですよ。
> # 最後にヒント書いたでしょ ;-)
>
> > そこでですが、ダイアログか何かのリソースを作成しそこにプログレスバー
> > を貼り付けてIDを獲得しなければならないのでしょうか。
>
> これは他のステータスバーとかのIDとダブってなければ何でもいいんです。
> とりあえず 1 でも 100 でも動くでしょう。
>
> afxres.h で定義されている AFX_IDW_* ってのは MFCが割り当てて使うんで
> この範囲は使うとまずいことになりがちですが、逆に言えば、それ以外の
> 値は MFC が関与しないので、勝手に使えると思います。

宮崎さんどうもありがとうございました。早速試してみます。


> > (株)エーディー 坂本
> メールに機種依存文字「かっこかぶ」とかを使うのは避けましょう。

ご指摘どうもありがとうございました。


(株) エーディー 坂本
e-mail s...@ad-jp.com
記事検索
Amazon.co.jp
  • ライブドアブログ