ソラマメブログ

2007年04月25日

音を鳴らそう(スクリプト初級第十七回)

今回のスクリプトは簡単です。
サウンドの再生についてはもっと早くに取り上げるべきでしたが、ついつい後回しになってしまいました(^^;

オブジェクトにちょっとした音を組み込むことは、簡単なわりに効果的です。
例えば照明のON/OFFをするときにスイッチ音を付けたり、アニメーションと一緒に効果音を付けたりするだけで、よりリアルで面白いものを実現することができます。
基本的にはスクリプトで実現できる音とは、効果音のことだと思ってください。
BGMのような長いサウンドを鳴らすことは容易ではありません。
というのも、SLにアップロード可能なサウンドは10秒以内に限られているためです。

今回は簡単な例として、以前作ったドアのスクリプトに、開閉の音を組み込んでみたいと思います。
サウンドを扱う関数

サウンドを扱う関数はいくつかあります。
最も基本的なのはllPlaySound()とllTriggerSound()です。

  llPlaySound(string sound, float volume)
  llTriggerSound(string sound, float volume)

引数は一緒です。
string型引数soundには、再生したいサウンドの名前かUUIDを指定します。
名前を指定した場合はそのサウンドがオブジェクトコンテンツの中になければいけません。

float型の引数volumeは、音量です。
指定できる数値は0.0~1.0になっています。
もともとのサウンドの音量で再生する場合は1.0(音量100%)、ミュートは0.0(音量0%)です(無音で再生することにどんな意味があるのか不明ですが(^^;)。

llPlaySound()とllTriggerSound()の違いは、音の発生源です。
llPlaySound()はオブジェクトから音を出します。
オブジェクトが移動すれば音も一緒に移動しますので、例えばスピーカーや楽器などはこちらを使います。
llTriggerSound()は関数を実行した時点のオブジェクトの位置から音を出します。
オブジェクトが移動しても、音は移動しません。場所固定になります。

またllPlaySound()をHUDで使った場合、音が聞こえるのはHUDの装着者のみです。
つまりボタン操作の音などを組み込んでも、周囲の人には聴こえません。
HUDから周囲の人にも聴こえるサウンドを鳴らすにはllTriggerSound()のほうを使わなければなりません。

用途に応じて二つの関数を使い分けますが、今回のドアに関してはまあ、どちらでもいいでしょう。
llTriggerSound()を使うことにします。

音の出るドア

以前作ったドアのスクリプトに、llTriggerSound()を組み込むだけで出来てしまいます。

rotation rot;
key sound_open = "cb340647-9680-dd5e-49c0-86edfa01b3ac";
key sound_close = "e7ff1054-003d-d134-66be-207573f2b535";


default
{
  state_entry()
  {
    rot = llGetRot();
    state close;
  }
}

state open {
  state_entry()
  {
    llTriggerSound(sound_open, 1.0);
    llSetRot(rot * llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD));
    llSetTimerEvent(30.0);
  }
  
  touch_start(integer total_number)
  {
    state close;
  }

  timer(){
    llSetTimerEvent(0);
    state close;
  }
}

state close {
  state_entry()
  {
    llSetRot(rot);
    llTriggerSound(sound_close, 1.0);
  }

  touch_start(integer total_number)
  {
    state open;
  }
}

出来ましたw
サウンドはSLにあらかじめ用意されている「きぃ~」「ばたん」を使いました。
最初に指定しているopenとcloseのUUIDがそれです。
このサウンドはもともとSLに用意されているので、ドアのコンテンツに入れなくても鳴らすことができます。

ループサウンド

えー・・・。
これだけで終わるのはさすがにアレなんで、もう少しサウンド系のお話を。

llPlaySound()とllTriggerSound()はどちらも一度きりの再生ですが、時にはサウンドを繰り返し鳴らしたい場合があります。
例えば水音とか。
滝や川の近くに水音をループ再生するオブジェクトを置くと、なかなかに雰囲気が出ます。

サウンドのループ再生にはllLoopSound()を使います。

  llLoopSound(string sound, float volume)

引数はllPlaySound()やllTriggerSound()と同じです。

ループ再生したサウンドの停止にはllStopSound()を使います。
この関数はllPlaySound()の停止にも使えます。
ですがllTriggerSound()を止めることはできませんので注意して下さい。

環境音用のスクリプトを一応載せておきましょう。
オーナーのタッチでサウンドのON/OFFを切り替えられるようにしてあるものです。

integer play=FALSE;
string sound="water_sound";

default {
  touch_start(integer detected){
    if (llDetectedKey(0) == llGetOwner()){
      play = !play;
      if (play) {
        llLoopSound(sound, 1.0);
      }else{
        llStopSound();
      }
    }
  }
}

サウンドのON/OFF状態を管理するために、integer型の変数playを用意しました。
FALSEというのは「偽」という意味です。
具体的には0のことです。

FALSEの反対はTRUEで、「真」のことです。
TRUEは1と等しい数値になっています。

「ON/OFF」や「正しい/誤っている」など、対の関係にあるデータを管理する際にはTRUEとFALSEを使うのが便利です。
というのも、

  play = !play;

上記スクリプトにこのような記述がありますが、この式はTRUEとFALSEを引っくり返す計算になっています。
「!」は「否定」を意味します。
すなわち「!play」は「playの逆」なので、もしもplayの値がTRUEならばFALSEに、FALSEならばTRUEになります。
タッチするたびにON/OFFを切り替えるのですから、これは便利です。

それからif文の条件のところに、ただ「play」としか書いていないのはどういうことでしょうか。

 if (play) {}

実は今まで使ってきたif文の条件ですが、全てTRUEとFALSEの値を返すのです。
例えば、

 if (cmd == "red") {}

などというif文を今までに書いていました。
「cmd == "red"」というのは実は計算式になっており、「cmdが"red"だったらTRUE、違ったらFALSEを返す」のです。

if文は()の中に書かれている値や計算式がTRUEかFALSEかを判断し、分岐処理を行います。

ですので、今回は単に

 if (play) {}

としか書いていません。
この場合、playの値がTREUのときのみ{}の中が実行されます。

このようにTREUとFALSEを管理する変数のことを、boolean型変数と言うことがあります。
実態はinteger型ですが、boolean型として使う場合にはTRUEとFALSEの値以外は通常使いません。

「ゼロかイチか」
「黒でばければ白」

みたいな、極めてデジタルなデータ型です。

・・・って、サウンドの関数があまりに簡単すぎるので、関係ないところを説明してみたりしました(^^;

今回のポイント

・サウンドの再生(1度のみ):
  llPlaySound(string sound, float volume)
  llTriggerSound(string sound, float volume)

・サウンドの再生(ループ):
  llLoopSound(string sound, float volume)

・サウンドの停止:
  llStopSound()

・boolean型:
  TRUE/真(実態は1)
  FALSE/偽(実態は0)

あんまりポイントのない回でした(^^;

とは言ってもサウンドを使えるようになると表現の幅は広がります。
今まで作ったスクリプトに組み込むだけで、面白いものが作れそうです。
座ったときに「ぶーー」と鳴るクッションとかw
ぜひぜひいろんなところで応用してみて下さい。

ではまた。


同じカテゴリー(初級スクリプト)の記事画像
衝突判定(スクリプト初級第二十三回)
カメラ制御(スクリプト初級第二十二回)
センサーを使おう(スクリプト初級第二十回)
HUDを作ろう(スクリプト初級第十六回)
prim間通信(スクリプト初級第十五回)
アニメさせよう(スクリプト初級第十三回)
同じカテゴリー(初級スクリプト)の記事
 衝突判定(スクリプト初級第二十三回) (2007-05-08 12:15)
 カメラ制御(スクリプト初級第二十二回) (2007-05-07 14:36)
 デモ商品を作ろう(スクリプト初級第二十一回) (2007-05-02 12:15)
 センサーを使おう(スクリプト初級第二十回) (2007-05-01 12:15)
 ステートのこと(スクリプト初級第十九回) (2007-04-27 12:15)
 rez!(スクリプト初級第十八回) (2007-04-26 12:15)
この記事へのコメント
いつも分かりやすい講義ありがとうございます。
講義十七回目でようやく追いつきました(^^;;
毎回毎回楽しみにしておりますので、頑張ってください!!
それでは復習しまーす(笑)
Posted by porsche at 2007年04月25日 22:24
>porscheさん

激励のコメントありがとうございます。
初級スクリプトも先はそう長くはありませんので、頑張って最後まで続けますね(^^;
Posted by Miz at 2007年04月27日 09:26
とても参考になりました。ありがとうございます。
ところで、鳥の鳴き声などはループかけると連続になってしまい
違和感があります。1分間に5回とか20秒あけて鳴るなどの場合は
どのようにすればよいのでしょう。

って質問するところではないかもしれません。

一応LLLoopSound で調べていますが今ひとつ見つかりません。
普通にLSLWikiを見ているだけだからかもしれませんが。

スクリプトが書けないのが致命的かもしれませんね。ww

あと、鳥の鳴き声、トンビの鳴き声など2つの音をループさせるなども
string sound="Song Sparrow";を二つかいたりしているのですが
なんとも。。。

もし可能でしたらその辺の記述もよろしくお願いします。
いや、可能だったら結構です。 lol
Posted by anjin Baxter at 2007年05月03日 11:11
>anjin Baxterさん

こんにちは(^^

一定間隔で一度ずつ鳴らすなら、タイマーイベントを使って一定時間ごとにllPlaySound(ループではなく一度だけ鳴らす関数)を実行してはどうでしょうか?

また、二つの音を入り混じって鳴らすには、スクリプトを二つ用意して、一方は鳥、もう一方はトンビにするのが簡単かもしれません。

default {
  state_entry(){
    llSetTimerEvent(20.0); // タイマーを20秒にセット
  }

  timer(){ // 20秒ごとに実行される
    llPlaySound("サウンド名",1.0);
  }
}


上記のスクリプトを二つ用意し、サウンド名のところを一方は鳥、一方はトンビに変え、それぞれに動かせば鳥・トンビの声が20秒ごとに聞こえてくると思います。
同じ位置から声がするのも面白くないでしょうから、それぞれのスクリプトは別の場所に配置するといいかもしれませんね(^^

タイマーの秒数等は調整してみて下さい~。
Posted by Miz at 2007年05月03日 18:57
とても参考になります。 内容も分かりやすく書かれていて、初心者の私でも大分と解ってまいりました。ボンヤリとですが(^^;)

サウンドループですが、ループさせる音源の長さは制御する事が出来るのでしょうか? SL内で、FREEのスクリプトに音声を作成し貼付けたところ、 作成したWAV(約8秒)が、約1秒位の間隔でしか、ループしてくれません。 もし、制御の表記がこのFREEスクリプトにあるとすると、どういった表記がされているのでしょうか?   大変恐縮致しますが、質問させて頂きました^^ 申し訳ありません。
Posted by p_suke at 2007年05月04日 02:21
>p_sukeさん

こんばんは。
llLoopSoundを使ってサウンドをループ再生した場合、サウンドの最後まで演奏してまた最初から再生されます。ループの間隔は指定できません。

p_sukeさんの使っているfreeのスクリプトでは、1秒単位で再生が繰り返されるということですので、二つ前のコメントで私が書いたような、タイマーによる繰り返し再生が行われているのではないかと思います。
そうだとしたら、タイマー部分をサウンドの秒数に合わせるか、あるいはタイマーではなくllLoopSoundを使った再生にすれば、正しくループされるはずです。

そのスクリプトの中身が見れるようなら、より正確に回答できると思いますので、詳しく中身を追求したいようでしたらin WorldでIMでも下さいまし(^^
Posted by Miz at 2007年05月05日 04:02
かっ!感激です!! ありがとうございます!   そうなんですか【llSetTimerEvent();】 で、そのような効果にもなるのですね!  是非追求したいので IMさせて頂きます☆  Miz様ご好意大変感謝致します。
 ですが、実は私プリムはグリグリ触っているのに、【IM】 の事etc.. 基本的なシステムあまり理解していないんです_ _;;)  申し訳ございません。 チョット学習してからお伺い致します。しばしお時間下さい^^ 
Posted by p_suke at 2007年05月05日 18:37
スクリプトの勉強をさせていただいています^^。
だんだん難しくなってきましたがなんとか理解しようとがんばっています。

「音の出るドア」のスクリプトをコンパイルしてみるとエラーがでました。
keyのopen、closeとstateのopen、closeで同じ名前なので、名前を変えてみるとうまくいきました。
そのままでもコンパイル通りますでしょうか?。
Posted by もに at 2007年05月06日 23:24
>もにさん

おっと、ご指摘の通りミスってました(^^;;
記事のコード修正しておきます。
ご迷惑をおかけしました。
Posted by Miz at 2007年05月07日 09:25
とっても分かりやすく丁寧に図解もあって、
まったくスクリプト等のC言語初心者にとっては、ありがたや~~です。
私も、ちょうど自動ドアの音の組み入れに挑戦しました。

もに さんと同じエラーが出て、ふん!っなんて ふて腐れておりました。
open close を直せばうまくいくのですか!
やってみま~す!
Posted by Kir at 2007年05月07日 18:16
>Kirさん

ご迷惑をおかけいたしました(><;

記事中のスクリプトでは、太字部分の変数の名前を
・sound_open
・sound_close
にそれぞれ変更しています。

これでエラーは出なくなるはずです。
Posted by Miz at 2007年05月07日 18:34
 やってみました! が・・・?
私のが自動ドアを作ってるので、touch 90度では あれれなんです
   (音はなっても、自動ドアの意味なし・・・・笑)
で、たぶん 
llTriggerSound(sound_open, 1.0);
llSetRot(rot * llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD));
このへんの  llEuler2Rot(<0.0, 0.0, 90.0> * DEG_TO_RAD));
問題だと予想はつくのですが、 llxxxxxxxx;
なんて、打つのやら分からなくて・・・
すいません、教えていただいて宜しいでしょうか?
Posted by Kir at 2007年05月07日 21:49
>Kirさん

自動ドアということは横にスライドする形でしょうか?
スライドということであれば・・・

llSetRotは回転ですので、スライドの場合はllSetPosを使います。
センサーの記事でスライドタイプのドアを作っていますので、そちらを参考にしてみて下さい。

・・・的外れだったらもう一度ご質問ください(^^;
Posted by Miz at 2007年05月08日 10:05
こんにちは。
楽器をつくっているんですねー。
サンプラーというか、シーケンサーいうか、そんなデモをやってます。
http://slurl.com/secondlife/SUZAKU/36/137/33

playsoundとloopsoundのmaster/slave使っています。
トリガーはSTOPでも止まらないということは連打すると重なってなるのかな?そうなると、幅が広がりますねー、いろいろ考え中です。(^^

それではお邪魔しましたー
Posted by gen at 2007年05月08日 17:45
>genさん

マスター/スレーブは上手く使うと面白い効果が出せそうですよねぇ~。
genさんのシーケンサー、今度拝見させていただきます(^^
Posted by Miz at 2007年05月09日 16:37
あの・・SLないにあるという効果音のUUIDとやらはどの様にすれば見つけることが出来るのでしょうか?
Posted by 美月 at 2007年05月25日 12:41
>美月さん

UUIDはインベントリウインドウで取り出すことができます。
試しに、インベントリの中の「ライブラリ」>「サウンド」の中にあるサウンドをどれでもいいので一つ選んで右クリックします。
「UUIDをコピー」のようなメニューがあると思いますので、それを選び、スクリプトのコードの画面に行って、CTRL+V(ウインドウズの場合ですが)で貼り付けることができます。

なお、サウンドのデータをオブジェクトのコンテンツの中に入れると、UUIDではなくサウンドの名前でも鳴らせます。
Posted by Miz at 2007年05月25日 12:54
探してみたのですが、ライブラリのサウンドにはジェスチャー系の音とクリック音しかありませんでした・・・・
Posted by 美月 at 2007年05月26日 03:15
>美月さん

他のサウンドは、インベントリのフィルタ機能を使うと探しやすいかもしれません。
うろ覚えですが、インベントリウインドウのメニューから、「フィルタ」のような項目を選んで、「サウンド」のみにチェックを入れると、サウンドデータだけが表示されるはずです。
Posted by Miz at 2007年05月26日 20:31
はじめて拝見させて頂きました。
非常にわかりやすく勉強になりました。有難うございます。
今後も拝見させて頂きますので宜しくお願いします。
Posted by NICO at 2007年08月03日 06:08
こんにちは、いつも拝見させて頂いております。先日教えて頂いた事を早速実行して、ますます楽しみを感じております。本日は、サウンドの件でお伺いしたいのですが、SLには10秒までの音しかアップロードできませんが、1曲をいつくかにわけてアップロードし、つなげて再生するにはどのようにしたら良いのでしょうか?お手数をおかけ致しますが、宜しくお願い致します。
Posted by Hiroe at 2007年09月08日 13:15
>Hiroeさん

私としてはあまり触れたくない部分ではありますが(ぇ
手法としては、
1、最初の10秒を再生
2、その間にllPreloadSound関数で次の10秒をロード
3、10秒経ったら次の10秒を再生
4、2番の処理に戻る
この繰り返しになります。

"jukebox"という名前で知られた一般的なスクリプトですので、探せばフリーのものもあるかと思います。
Posted by MizMiz at 2007年09月08日 13:50
1)IBMホームページビルダーがJust Systemに移管された事により「Hot Mediaクリエーター」アニメーションで使用されていた「確認音」ファイルが使用出来なくなりました。
「確認音」に関する資料を探しておりましたところ、2007年04月25日の「音を鳴らそう(スクリプト初級第十七回9)を拝見致しました。
つきましては、「音の出るドア」の下に記載されております「以前作ったドアーのスクリプト」に付きましてア左欄にありますーカイブなどで探しましたが見つかりませんので、当該スクリプトを拝見致したく思いますのでご指導お願い申しあげますが如何でしょうか。

2)「音の出るドアー」の下にあります「スクリプト」は<META>表示で<head>~</head>間に挿入、または<body>~</bidy>間に挿入でしょうか。
佐藤
Posted by sato at 2010年11月20日 19:58
 
<ご注意>
書き込まれた内容は公開され、ブログの持ち主だけが削除できます。