[Message Prev][Message Next][Thread Prev][Thread Next][Message Index][Thread Index]

Re: [MD:4204] Sound support



私は、日曜日、校正中...^^;;;

At Sun, 23 Feb 2003 10:38:56 +0900,
MIYOSHI Masanori wrote:

> >>>>> [meadow-develop : No.4207] にて
> >>>>> "himi" = MIYASHITA Hisashi(宮下 尚:HIMI) <himi@xxxxxxxxxxx> さんは書きました:
> himi> 理想的にはこっちですが、それは当分先のことなので、まず、MCIを入れるのは
> himi> それほど悪くない選択だと思います。大事なのは、まず、MCIに忠実な下位層を
> himi> 作成し、その後、Emacsの上位層のelisp APIをemulateするという構成が望ましいと
> himi> 思われます。MCIは、ほとんどcommand送るだけの単純構成だし、primitive APIも
> himi> 簡単に作れるでしょう。
> 
> 実験的に、手元で、次の primitive function を実装してみました。
> 
> (mw32-mci-send-string COMMAND NOTIFY-CALLBACK-FUNC NOTIFY-CALLBACK-ARG)
> (mw32-mci-get-error-string ERROR-CODE)

恐るべし。もう出来てしまうとは。^^;;;

> 次のようにして WAV データを再生できています。
> 
> (mw32-mci-send-string "open c:/WINDOWS/Media/tada.wav alias x")
> (mw32-mci-send-string "play x")
> (mw32-mci-send-string "close x")
> 
> で、質問があります。
> 
> (1) 利用する MCI レイヤ
> MCI にもいろんなレイヤがあるようなのですが、himi さんが想定してい
> るのは、この文字列でコマンドを送るレイヤでいいのでしょうか?

はい。まさにそういうものを想定していました。^^;;;

> (2) コールバックの実装
> ループ再生のためなどに、再生完了時に発生する MM_MCINOTIFY イベン
> トをひろってコールバック関数を実行しようと思っているのですが、う
> まくいきません。
> 
> NOTIFY-CALLBACK-FUNC を safe_call()で実行するときにエラーとなりま
> す。

それはいかんです。

> 多分、メッセージスレッドで safe_call() しているのが悪いと思われる
> ので、メインスレッドで実行させたいのですが、その方法が分かりませ
> ん。
> 
> 分かる方教えてください。
> 
> ;; 多分 Emacs イベントを介すればできそうだけど、よく分かりません。

もし本格的にやるなら、当然、Emacs eventを使うべきです。
## サボる手もあるけど、それは設計上良くないので、ここでは触れません。

emacs eventを拡張するには、まず、termhooks.hをいじります。ここに、
まず、新しいevent_kindを追加しましょう。候補としては、mw32_mci_eventが
良いかな。^^;;;

次に、lispy eventを定義します。これは、Lisp Objectとして、eventがどう
あらわされるかを決定するものです。Emacsは、XEmacsと違って、この辺が
例によっていい加減です。どうせ、MCIは、今までになかったeventの種類なので
自分で定義した方が良いでしょうね。

(mw32-mci <MCI-EVENT-TYPE> <DEVICE-ID> [EVENT-TYPE-SPECIFIC-PARAMETER])

こんな感じでよいかな。(対応を取る為に、mw32-mci-send-stringなどで
MCI命令を発行した後、device IDを返却するようにすれば良いでしょう。)

これは、make_lispy_event()で定義されます。
(もういい加減構造化してやりたい関数の筆頭:-P)

実際の定義はこんな感じになっています。
ここで、emacs_event構造体をLisp Objectに変換します。

    case w32_mouse_wheel:
      {
	int part, row, column;
	int delta = event->code;
	FRAME_PTR f;
	Lisp_Object window;
	Lisp_Object posn;
	Lisp_Object position, head;

	f = XFRAME(event->frame_or_window);
	if (! FRAME_LIVE_P (f))
	  return Qnil;

	pixel_to_glyph_coords (f, XINT (event->x), XINT (event->y),
			       &column, &row, NULL, 1);
	window = window_from_coordinates (f, XINT(event->x),
					  XINT(event->y), &part, 0);

	if (!WINDOWP (window))
	  {
	    window = event->frame_or_window;
	    posn = Qnil;
	  }
	else
	  {
	    int pixcolumn, pixrow;
	    struct window *w = XWINDOW (window);
	    column -= XINT (w->left);
	    row -= XINT (w->top);
	    glyph_to_pixel_coords (w, column, row, &pixcolumn, &pixrow);
	    XSETINT (event->x, pixcolumn);
	    XSETINT (event->y, pixrow);

	    if (part == 1)
	      posn = Qmode_line;
	    else if (part == 2)
	      posn = Qvertical_line;
	    else
	      {
		Lisp_Object object;
		struct display_pos p;
		buffer_posn_from_coords (w, &column, &row,
					 &object, &p);
		posn = make_number (CHARPOS (p.pos));
	      }
	  }

	position =
	  Fcons (window,
		 Fcons (posn,
			Fcons (Fcons(event->x, event->y),
			       Fcons (make_number (event->timestamp),
				      Fcons (make_number(delta), Qnil)))));

	/* Always treat mouse wheel events as clicks. */
	event->modifiers |= click_modifier;

	head = modify_event_symbol (0,
				    event->modifiers,
				    Qmouse_click, Qnil,
				    lispy_mouse_wheel_names,
				    &mouse_wheel_syms,
				    (sizeof (lispy_mouse_wheel_names)
				     / sizeof (lispy_mouse_wheel_names[0])));
	return Fcons (head,
		      Fcons (position,
			     Qnil));
      }
--------------------------------------------------------------------------------

実際に、emacs eventを発行するのは、たとえば、mw32_drop_file_handlerとか、
mw32_mouse_wheel_handlerを見ればよいかな。今回必要なeventは、一回につき一つだろうから、
これで十分。
int 
mw32_mouse_wheel_handler (FRAME_PTR frame,
			  MSG* msg,
			  struct input_event* emacs_event)
{
  struct mw32_display_info *dpyinfo = FRAME_MW32_DISPLAY_INFO(frame);
  POINT pt;

  /* Sony VAIO Jog Dial Utility sends WM_MOUSEWHEEL with the posotion
     guessed by active window. Here replace it by last mouse position
     stored as last_mouse_motion_message. There is no side effect,
     maybe.. 2001/03/16 K. Horiguchi */

  pt.x = (signed short) LOWORD(last_mouse_motion_message.lParam);
  pt.y = (signed short) HIWORD(last_mouse_motion_message.lParam);

/*
  pt.x = (signed short) LOWORD(msg->lParam);
  pt.y = (signed short) HIWORD(msg->lParam);
  ScreenToClient(msg->hwnd, &pt);
*/

  emacs_event->kind = w32_mouse_wheel;
  emacs_event->code = (signed short) HIWORD(msg->wParam);
  emacs_event->modifiers = MW32GETMODIFIER (dpyinfo);
  XSETINT (emacs_event->x, pt.x);
  XSETINT (emacs_event->y, pt.y);
  XSETFRAME (emacs_event->frame_or_window, frame);
  emacs_event->timestamp = msg->time;

  return 1;
}

この関数を、mw32_message_loop()から呼び出せばよいというわけ。

やるべきことは以上。そんなに難しくないはず。

from himi