5
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Elixirで「メロディ」を鳴らす

Last updated at Posted at 2024-09-03

Elixirで「ドレミファソラシド」を鳴らすの続編です

前提条件

  • OS Ubuntu 22.04

仕様

  • 前回のElixirで「ドレミファソラシド」を鳴らすの仕様を継承する
  • 4音符/8音符/16音符の概念を追加

ソースを書く

lib/sox.ex
defmodule Sox do
  @a4_frequency 440
  @a4_note_no 69
  @bpm 180

  @moduledoc """
  Documentation for `Sox`.
  """

  @doc """
  Hello world.

  ## Examples

      iex> Sox.hello()
      :ok

  """
  def hello do
    note1 = [
      {78, 8},
      {77, 16},
      {0, 16},
      {73, 16},
      {0, 16},
      {0, 8},
      {78, 16},
      {0, 16},
      {77, 16},
      {73, 8},
      {0, 16},
      {0, 8}
    ]

    note2 = [{75, 16}, {75, 16}, {0, 16}, {75, 16}, {0, 16}, {75, 8}, {0, 16}]
    note3 = note_shift(note2, -4)
    note4 = note_shift(note2, 3)

    note1
    |> Enum.concat(note1)
    |> Enum.concat(note2)
    |> Enum.concat(note3)
    |> Enum.concat(note2)
    |> Enum.concat(note4)
    |> List.duplicate(2)
    |> List.flatten()
    |> Enum.each(&play(&1))

    :ok
  end

  def note_shift({0, time}, _), do: {0, time}
  def note_shift({note, time}, shift), do: {note + shift, time}

  def note_shift(notes, shift) when is_list(notes) do
    notes
    |> Enum.map(&note_shift(&1, shift))
  end

  def note_no_to_frequency(@a4_note_no), do: @a4_frequency

  def note_no_to_frequency(note) when note < @a4_note_no,
    do: @a4_frequency / :math.pow(2, 1 / 12 * (@a4_note_no - note))

  def note_no_to_frequency(note) when note > @a4_note_no,
    do: @a4_frequency * :math.pow(2, 1 / 12 * (note - @a4_note_no))

  def play({note, time}), do: play(note, time)

  def play(0, time) do
    sec = get_sec(time)
    play_cmd(0, sec)
  end

  def play(note, time) do
    sec = get_sec(time)

    note_no_to_frequency(note)
    |> play_cmd(sec)
  end

  def play_cmd(frequency, time), do: System.cmd("play", ~w"-n synth #{time} sin #{frequency}")

  def get_sec(1), do: get_sec(4) * 4
  def get_sec(2), do: get_sec(4) * 2
  def get_sec(4), do: 60 / @bpm
  def get_sec(8), do: get_sec(4) / 2
  def get_sec(16), do: get_sec(4) / 4
end

実行

$ mix test

ソース(github)

5
2
0

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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?