喫茶XRAYトップページ

[スレッド全体
]

[10283] Msg.lParamで示されたポインタで配列を操作したい返信 削除
2016/8/10 (水) 20:32:05 taki
マスター、みなさん 助けてください。

ダブルバッファで連続して音データを再生するプログラムの一部です。
MM_WOM_DONEで返されたメッセージのMsg.lParamにwhdr1またはwhdr2の
どちらかのアドレスが格納されて返ってきます。
そのアドレスでabuf1もしくはabuf2の配列を操作したいのです。

以下がソースの一部です。長くてごめんなさい。

type
  Tabuf = array[1..44100] of smallint;

var
  abuf1:Tabuf;   // abuf1:array[1..44100] of smallint;
  abuf2:Tabuf;   // abuf2:array[1..44100] of smallint;
 
  whdr1,whdr2:Twavehdr;

// 再生開始
procedure TForm1.StartPlay;
begin
  // ウェブヘッダーをセット
  with whdr1 do
  begin
    lpdata := @abuf1;
    dwbufferlength := sizeof(abuf1);
    dwbytesrecorded := 0;
    dwUser := 0;
    dwFlags := WHDR_BEGINLOOP or WHDR_ENDLOOP;
    dwloops := 1;
    lpNext := NIL;
    reserved := 0;
  end;

  with whdr2 do
  begin
    lpdata := @abuf2;
    dwbufferlength := sizeof(abuf2);
    dwbytesrecorded := 0;
    dwUser := 0;
    dwFlags := WHDR_BEGINLOOP or WHDR_ENDLOOP;
    dwloops := 1;
    lpNext := NIL;
    reserved := 0;
  end;

  // 出力デバイスを開く
  waveOutOpen(@hwo,WAVE_MAPPER,@wfe,handle,0,CALLBACK_WINDOW);
  // 波形データを準備する
  waveOutPrepareHeader(hwo,@whdr1,sizeof(Twavehdr));
  waveOutPrepareHeader(hwo,@whdr2,sizeof(Twavehdr));
  //
end;

// ここが問題の手続き
procedure SetWaveData(buf:Pointer);  // 引数で受け取る時はPointer型
var
  i:integer;
begin
  for i := 1 to Length(buf) do begin   // 内部では配列として操作したい
    buf[i] := XXX;
  end;
end;

// メッセージ処理
procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
begin

  ・・・略・・・

  // MM_WOM_DONE ///////////////////////
  if Msg.message = MM_WOM_DONE then begin

  // Msg.lParam には、出力バッファを表す WAVEHDR 構造体へのポインタが格納されています

  // SetWaveData手続きでabuf1もしくはabuf2にデータをセットする
    SetWaveData(Twavehdr(Pointer(Msg.lParam)^).lpData));  // <-ここで使いたい

 // waveOutWrite(hwo,@whdr1,sizeof(Twavehdr));
    waveOutWrite(hwo,Msg.lParam,sizeof(Twavehdr));  // <-こんな感じでも使えるかも
 
  end;

  ・・・略・・・

end;


Tabuf(buf)とかすると、「正しくない型キャスト」と叱られてしまいました。


[10284] Re: Msg.lParamで示されたポインタで配列を操作したい返信 削除
2016/8/10 (水) 22:16:49 Mr.XRAY
▼ takiさん

> そのアドレスでabuf1もしくはabuf2の配列を操作したいのです。

こういうのは難しいですね.
コーディングの好みもあるかも知れません.
メッセージの処理の部分だけ.例えばです.

動作確認は Windows 7 U64(SP1) + Delphi XE(UP1) Pro です.

implementation

{$R *.dfm}

type
  Tabuf = array[1..44100] of smallint;

var
  abuf1:Tabuf;

procedure TForm1.Button1Click(Sender: TObject);
begin
  abuf1[1] := 100;
//  PostMessage(Handle, MM_WOM_DONE, 0, LPARAM(@abuf1[1]));
  PostMessage(Handle, MM_WOM_DONE, 0, LPARAM(@abuf1));
end;

// 引数の型をTaBufにした方が処理がしやすいかな,と...
procedure SetWaveData(var buf: Tabuf);
begin
  buf[1] := buf[1] + 500;
  buf[3] := 133;
end;

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LpBuf : ^Tabuf;
  LText  : string;
begin
  if Msg.message = MM_WOM_DONE then begin
    LpBuf := Pointer(Msg.lParam);
    SetWaveData(LpBuf^);

    LText := IntToStr(LpBuf[1]) + sLineBreak +  IntToStr(LpBuf[3]);
    MessageBox(Handle, PChar(LText), '結果', MB_ICONINFORMATION);
  end;
end;



[10286] ポインタ型を定義する方法もある返信 削除
2016/8/10 (水) 22:56:30 Mr.XRAY
> コーディングの好みもあるかも知れません.

よく見かけるのは,Type 宣言の時にポインタ型も定義してしまうやつですね.

type
  Pabuf = ^Tabuf;      //分かりにくかったら PTabuf でもいいと思う...
  Tabuf = array[1..44100] of smallint;

そうするとキャストの処理の見通しがよくなる場合があります.
Pointer 等という味気のないのを使う必要がなくなります.

procedure TForm1.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  LpBuf : Pabuf;
  LText : string;
begin
  if Msg.message = MM_WOM_DONE then begin
    LpBuf := Pabuf(Msg.lParam);
    SetWaveData(LpBuf^);

    LText := IntToStr(LpBuf[1]) + sLineBreak +  IntToStr(LpBuf[3]);
    MessageBox(Handle, PChar(LText), '結果', MB_ICONINFORMATION);
  end;
end;


[10287] Re: ポインタ型を定義する方法もある返信 削除
2016/8/10 (水) 23:09:09 Mr.XRAY
> よく見かけるのは,Type 宣言の時にポインタ型も定義してしまうやつですね.

そうすると,SetWaveData(LpBuf) の引数の逆参照を使わずに
以下のように SetWaveData の引数にポインタ型が使用でき,
var が必要なくなります.

procedure SetWaveData(buf: Pabuf);
begin
  buf[1] := buf[1] + 500;
  buf[3] := 133;
end;


[10288] Re2: ポインタ型を定義する方法もある返信 削除
2016/8/11 (木) 07:41:39 taki
▼ Mr.XRAYさん
> > よく見かけるのは,Type 宣言の時にポインタ型も定義してしまうやつですね.
>
> そうすると,SetWaveData(LpBuf) の引数の逆参照を使わずに
> 以下のように SetWaveData の引数にポインタ型が使用でき,
> var が必要なくなります.
>


マスター ありがとうございます。

ありがたや、ありがたや。


[10289] Re3: ポインタ型を定義する方法もある返信 削除
2016/8/11 (木) 12:10:10 Mr.XRAY
>type
>  Pabuf = ^Tabuf;      //分かりにくかったら PTabuf でもいいと思う...
>  Tabuf = array[1..44100] of smallint;


このようなポインタ型の使用は,実はかなり強力です.
Pointer では型の情報は分かりません.
上の Pabuf は Tabuf のポインタ型というのが明確です.

特にレコード型のメンバを操作する時は便利です.
VCL のソースコード内をみてみると多くのレコード型で定義されています.


[10294] Re4: ポインタ型を定義する方法もある返信 削除
2016/8/11 (木) 16:33:31 taki
▼ Mr.XRAYさん
 
> このようなポインタ型の使用は,実はかなり強力です.
> Pointer では型の情報は分かりません.
> 上の Pabuf は Tabuf のポインタ型というのが明確です.
>


マスターのおかげでプログラムは動くようになりました。

Pointer型だけでは型の情報が無いので、
Tabuf = array[1..44100] of smallint; を定義する事まで
思いついたのですが、それからが分かりませんでした。

SetWaveData()手続きで引数を受け取る前に型キャストするべき
だったのですね。

ポインタを手続きの引数で扱う時の注意については、
「今更きけない 動的配列…」でも学習したはずなんだけどなぁ。
「壁」を乗り越えられていなかったみたい。

いや、忘却(もしくは加齢)と言う絶望的な「壁」かも…。


[10295] 優秀な頭脳返信 削除
2016/8/11 (木) 16:40:50 Mr.XRAY
> 「今更きけない 動的配列…」でも学習したはずなんだけどなぁ。
> 「壁」を乗り越えられていなかったみたい。


ホホホッ.
私は,人にパソコン関係を教える時はこう言っています.

『分からなくなったら,何度でも同じこと訊いて.
でも,私と違って,自分は 1 回訊いただけで完全に理解できる脳みそを
持っているという自信があるなら別だけどね』

今,オリンピックの最中です.
水泳,体操が話題になっていますが,どんな選手も,何回も何回も同じことを
練習しているんです.


[▼次のスレッド]
INCM/CMT
Cyclamen v3.82