LoginSignup
5

More than 1 year has passed since last update.

Macでマックのティロリ音が聞けるコマンドを作った

Posted at

2023年1月17日にマクドナルドの公式Twitterよりポテトを揚げる音、通称「ティロリサウンド」が配布されました。

ツイートを見る感じだと好きに使って良さそうなので、何か面白いことに使えないかな...と考えていた所、こんなアイディアを思いつきました。

  • ターミナルからコマンド経由で「ティロリ♪ ティロリ♪...」と流す
  • マックのポテトが食べたくなる
  • リモートワークで家に引きこもってるけど、マックに行かねばならなくなる
  • 外出することで運動になる

風が吹けば桶屋が儲かるという言葉もあるので、さっそくelixirでティロリサウンドを再生するコマンドを作ってみました。

作ったもの

まずは完成品をご覧ください。

ターミナルに「poteto」と打ち込むと「ティロリ♪ティロリ♪...」とサウンドが再生されます。そのまま、30秒程度、サウンドが再生し終わるまで放置するか、「stop」と打ち込むことで再生を停止させることが出来ます。

では、どのように作ったかを順に紹介していきます。

プロジェクト作成

まずはmixを使って新しいプロジェクトを作成します。今回はコマンド名に合わせて「poteto」としました。

$ mix new poteto
* creating README.md
* creating .formatter.exs
:
Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

    cd poteto
    mix test

Run "mix help" for more commands.

処理の実装

ではlib/poteto.exにメインの処理を記述していきます。今回はescriptを使って、ビルドしてコマンドとして実行できるようにしたいので、main関数を定義します。
main関数は1つ引数を受け取る必要がありますが、今回はターミナルからコマンドを受け取る予定はありませんので、アンダーラインを付与して使用しない変数だと明示しておきます。

lib/poteto.ex
defmodule Poteto do
  def main(_args) do
  end
end

サウンドの再生

調査の結果、自力で頑張ってサウンドを再生させるのはかなり大変...ということが分かりました。
「なんとかならないかな?」と思案していた所、Macにはafplayという指定したファイルパスの音声ファイルを再生するコマンドがあることを発見しました。

このコマンドをSysytem.cmd経由で呼び出します。再生を停止させる場合は同様にSystem.cmd経由でkillall afplayで停止させます。欠点としてafplayで再生した音声が全て停止してしまうという問題がありますが、今回は目を瞑ります。。。

def play_sound(sound_path) do
  System.cmd("afplay", [sound_path])
end

def stop_sound do
  System.cmd("killall", ["afplay"])
end

OSによる処理の分岐

Macの場合にはafplayコマンドを使用しますが、他のOSでは別のコマンドを使用することを想定して、パターンマッチで処理を分岐できるようにしました。
もし興味があれば、レポジトリを公開しているので、別OSの実装のPRを投げて頂けると嬉しいです。

lib/poteto.ex
defp command_exec({ :win32, _ }, _function, _args), do: :pass
defp command_exec({ :unix, :darwin }, function, args), do: apply(OS.Darwin, function, args)
defp command_exec(_, _function, _args), do: :pass

モジュールはマッチしてOSの情報に合わせて、対応するモジュールの関数を動的に呼び出すようにしました。今回はdarwinに対応するOS.Darwinが使用されます。

lib/os/darwin.ex
defmodule OS.Darwin do
  def play_sound(sound_path) do
    System.cmd("afplay", [sound_path])
  end

  def stop_sound do
    System.cmd("killall", ["afplay"])
  end
end

あとは「stop」させるためにplay_sound関数の呼び出しを別プロセスで行い、ユーザー入力を受け付けるreceiver関数を定義してあげれば出来上がりです。

lib/poteto.ex
defmodule Poteto do
  def main(_args) do
    spawn(fn -> command_exec(:os.type(), :play_sound, ["/Users/takamizawa46/sounds/poteto_sounds.mp3"]) end)

    IO.puts("🍟「再生を停止したい場合は 'stop' と入力して下さい」")
    receiver()
  end

  defp receiver do
    case IO.gets("") do
      "stop\n" -> command_exec(:os.type(), :stop_sound, [])
      _ -> receiver()
    end
  end

  defp command_exec({ :win32, _ }, _function, _args), do: :pass
  defp command_exec({ :unix, :darwin }, function, args), do: apply(OS.Darwin, function, args)
  defp command_exec(_, _function, _args), do: :pass

end

実行ファイルの作成

音声ファイルのファイルパスを絶対パスにしたのはビルド後にPATHを通した際に、ファイルが参照出来なくなるエラーを確認したためです。合わせてビルド出来ないか試しましたが、そういったオプションは自分が調べた限りでは発見出来ませんでしたので、この方法を採用しました。

あとはmix escript.buildを実行して、実行ファイル(poteto)を作成します。これでターミナルから./potetoとすればティロリ音が再生されます。お好みでPATHを通して、どこからでも実行できるようにすれば完成です。

bashᕙ( ˙-˙ )ᕗ takamizawa46@ ~/elixir/poteto  $ ./poteto
🍟「再生を停止したい場合は 'stop' と入力して下さい」
stop

コードの全体像はレポジトリをご覧ください。

最後に

思いつきのネタでしたが、無事に実装出来てよかったです。
特にサウンドを再生するということはやったことがなかったので良い勉強になりました。今回はafplayという手段を選択しましたが、もし他にアイディアや知識をお持ちの方がいたら、ご教授頂ければと思います。

普段は個人ブログにリモートワークやチームビルディング、プログラミング言語などの記事を書いていますので、ぜひご覧ください。

では、ティロリ音を聞いてポテトが食べたくなったので、マックに行ってきます🏃‍♂️🏃‍♂️🏃‍♂️

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5