游星通信

作ったものの紹介など

Howler.jsで簡単に自然にループするBGMを実装する

※メモ書きに近いです

やるきっかけ

HTML5ゲーで細かくてシームレスなループをさせるのってどうするの?と思い、何とか自己流でやってみた。

howler.js(v2.0系)使用。

要件

  • 再生開始時は普通に曲頭から
  • ループ終点までいったら今度は曲頭ではなく、ループ開始地点にシークして2週目開始
  • 以後、ル開始~終点で無限ループさせる

実装

html部

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>howler.js ループテスト</title>
</head>
<body>

<script src="howler.jsへのパス"></script>
<script src="./main.js"></script>
</body>
</html>

特にHTML側で変わったことはしません。

スクリプト部(main.js)

デフォルトHowlクラスの拡張をします。

class Music extends Howl {
  constructor (data, debugStart=0) {
    const params = {
      src: [data.src],
      preload: false,
      // オーデイオスプライト設定
      sprite: {
        start: [debugStart, data.loopEnd-debugStart],
        loop: [data.loopStart, data.loopEnd - data.loopStart, true],
      },
    };
    super(params);
    this.load();
  }

  playMusic () {
    this.play("start");

    // 一周目の再生終了を検知したらループ部に入る
    this.once('end', ()=> {
      this.play("loop");
    });
  }
}

howlerにはオーデイオスプライト機能があります。 スプライトシートのいわばサウンド版で、複数の音源を一つの音源ファイルにまとめ上げ、範囲を指定することでそれぞれの音を鳴らすことができます。

通常は効果音を一つのファイルにまとめて通信量を減らす目的で使うそうだけど、この機能はシームレスなループにも使えます。
範囲はそれぞれ最初はstartで、2週目以降に無限ループするのがloopと名前をつけます。

sprite設定は見ての通り配列で設定を渡し、それぞれ[ 開始位置(msec), 範囲長(duration), ループするかどうか ]で指定。 durationは(ル終 - ル開)で動的に計算する。

debugStartについては後述。

流す

// loopStart, loopEndはそれぞれミリ秒単位でのル開始、終点
const musicData = {
  src: "./music.mp3",
  loopStart: 17950,
  loopEnd: 126936,
};

const music = new Music(musicData);
music.onload = function() {
  this.playMusic();
};

後はシンプルにロード&再生。

デバッグ再生

ル終点までわざわざ再生して接続確認するのはだるいです。 ということで最初から終点間際にして再生確認するため、 第二引数で開始位置を渡せるようにすると便利。

// ル終点2秒前にシークした状態で再生
var music = new Music(musicData, musicData.loopEnd - 2000);
music.onload = function() {
  this.playMusic(); // すぐループに入る
};

おまけ:ループポイント探しの旅

自分で作曲とかしない限り、ロイヤリティフリー音源を使うことも多いが、大体の場合、ループポイントは実際に音源を聞いて探すしかない。(RPGツクール用に親切にループポイントを付記した音源もたまにあるけど)

基本的には以下のような感じで探ってます。

f:id:pentamania:20180725131101p:plain

(メニューの「編集」 -> 「設定」で開いたウィンドウの「トラック」を選び、Auto-scroll if head unpinnedのチェックをはずす)

  • ループが綺麗につながりそうな範囲を指定(大雑把で良い)
  • ループ終点辺りでShiftを押しながら上部のタイムライン部を押してループ再生、つながり具合を確かめる

f:id:pentamania:20180725132642p:plain

  • 拡大して接続が自然になるまで範囲を微調整 選択範囲の端(マウスアイコンが手に変わる)をドラッグする
  • いい感じになったら下の範囲開始秒と終点秒を記録しておく f:id:pentamania:20180725130358p:plain

PxB Map Editor アップデートした【v0.3.0】

<追記>
バグで背景に動画が指定できなくなってます。後日修正予定
2018/04/12 直しました
2018/05/20 処理が重くなり、特に背景に動画を使用するとかなり処理落ちするようになってしまいました。原因究明中ですが、どうしても背景に動画を使いたい場合、v0.2.0の使用を推奨します。
</追記終わり>

クロスでビーツな感じのクールな譜面が作れるツール「PxB Map Editor」をアップデートしました。

ここからダウンロード

後述のインストーラ版と、v0.2.0以前と同じポータブルexe版があります。好みの方を選んでDLして下さい。

PxB Map Editorについてはこちら

pentamania.hatenablog.com

何が変わったの

  1. 5x7以外のグリッド配置ができるようになった
  2. pxbpファイルに音源、背景のパスを含めないようにした
  3. BPMを変化させた際、計算ミスによりチャートが必要以上にのびて重くなるバグ修正
  4. BPM変化によるノーツの動きがなめらかになった
  5. エフェクト刷新 その他処理を最適化などの細かい変更

1:5x7で固定だったグリッドもようやく変更できるようになりました。

2:音源、背景のパスは個人情報になりうるので省くようにした。これでファイルそのものを配布しやすくなりました。
地味だけど今までの使い勝手を変えずに実装するのは結構手間取った...

3:そのまんま。計算関連のバグはまだありそうな気が...

4:雑だったBPM関連の実装を見直して、今まではハードランディングという感じだったのを文字通りソフトランディングするようになった。

5:けっこう改善要望があったような気がするエフェクトをより本家っぽくしました。

元々エフェクト作成ツールで作り、スプライトシートに出力してそれをアニメーションさせていたけど、ツールがとにかく使いづらくて嫌になり、ゲーム中に動的に生成・アニメーションさせる方向に切り替えた。(ちなみに本家のエフェクトもよく見ると火花の散り方がランダムなので、似たような作り方になってるかもしれない)

インストーラ

今回はインストーラ版も用意しました。 32bit、64bitで対応する方を自動的にインストールするっぽいです。(32bit機が無くて確認できない…)

ちなみにインストーラ版のほうが起動が早いです。(というかexe版は圧縮してる分、起動が遅い模様)それ以外は特に違いはありません。 ちなみにインストール済みの場合、アップデートを行います。

必要なのか微妙なところだけど、ポータブルexe版もついでに32bit対応しています。

PxB Playground(仮)

PxBはjavascript、すなわちweb技術で作られてるので、遊ぼうと思えばモバイル含めたブラウザでも遊ぶことができる。 そこでやや力技だけど音源とプロジェクトファイルを(一時的に)アップロードする形で遊べるようサイトを用意しました。(ブラウザではユーザーのデータに直接触れないため、このような回りくどい仕組みになってしまう。何とかしたい)

pxb-playground.firebaseapp.com

使い方はiPad等で上のサイトへアクセスして、オンラインストレージ(dropbox等)を通してpxbpファイルと音源ファイルをセット → Play を押すだけ

注意点として

  • ファイル名に日本語が含まれていると上手く動作しないこともある
  • 「一応できる」レベルなのであまり期待せずに
  • iOSは8以上はでないとうまくいきません。(というかアップロードできない模様) androidはよくわからないけど5.0以上でないと厳しいかも。

(一ヶ月に一回アップデートできたらなぁと思ってたけど3ヶ月経ってた…)

【メモ】npmをアップデートしたらnpmコマンドがpermission deniedになったけど再起動したら治った

環境

  • OS:windows 10 64bit
  • Nodeバージョン管理:nodist v0.8.8
  • 黒い画面:git bash

はじめに

ある日、npmのアップデートがあるよ!と言われ、うっかりnpm i -g npmしてしまったらエラーになり(管理者権限で実行しろ云々と怒られる)、 そしたらnpmコマンドが実行できなくなってしまい、困る。 (本来ならバージョン管理に使ってるnodistを通してnpmをアップデートするべきだった)

色々探った結果、コマンドプロンプト(cmd.exe)等では普通に実行できるが、普段使っているbashではエラーになることがわかった。

3つのnpm?

エラー内容によると /c/Program Files (x86)/Nodist/bin/npm を実行しようとしてpermission deniedとなっていた。
なので /c/Program Files (x86)/Nodist/bin/の中身を見てみると

  • npm
  • npm.cmd
  • npm.exe

と、npmとつくものが3つも出てきて混乱する。

どうやらcmdでは直接「npm.exe」を実行するので問題ないが、 git bashでは最初に引っかかる「npm」を実行しようとしてエラーになっているようだった。

permissionを正しく設定していればいいのかと思ったけど、 「npm」のpermissionの設定が何故かできない…。

再起動で復活

ネット上で
「ぶっ壊れてpermissionを変更できないファイルができちゃって困ってたけど、再起動したら治ったよ!」
という文言を発見する。

で、再起動してみたら前述の「npm」ファイルが綺麗さっぱり消えてた。 どうやらアップデートエラー時に残ったゴミファイル?が悪さしていたようだ。 めでたしめでたし…

感想

npmのアップデートは前も実行に失敗して苦労したが、今回もやってしまった。 準備もせず、むやみに行うのはやめよう(自省)
ただ、何となく再起動して何となく解決、というわけではなく原因っぽいのは分かった上で直せたのでとりあえず満足。

参考