Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Sound recording stream

sound_recording_stream.livemd

Sound recording stream

Mix.install([
  {:zexray, github: "jn-jairo/zexray", depth: 1}
])

Code example

Example complexity rating: [★☆☆☆] 1/4

defmodule Example do
  use GenServer

  use Zexray.Enum
  use Zexray.Type

  @screen_width 800
  @screen_height 450
  @title "zexray [audio] example - sound recording stream"

  @sample_rate 44_100
  @sample_size 32
  @channels 1

  @name __MODULE__

  # Client

  def start_link(opts \\ []) do
    GenServer.start_link(__MODULE__, opts, name: @name)
  end

  def stop() do
    GenServer.stop(@name, :normal)
  end

  # Server

  @impl true
  def init(_opts) do
    Zexray.Window.init(@screen_width, @screen_height, @title)
    Zexray.Audio.init()

    Zexray.Audio.init_record_stream(
      @sample_rate,
      @sample_size,
      @channels
    )

    # Set our game to run at 60 frames-per-second
    Zexray.Timing.set_target_fps(60)

    wave =
      type_wave(
        frame_count: 0,
        sample_rate: @sample_rate,
        sample_size: @sample_size,
        channels: @channels,
        data: []
      )

    next_frame()

    {:ok, {wave, nil}}
  end

  @impl true
  def terminate(_reason, state) do
    Zexray.Resource.free(state)

    Zexray.Audio.close_record_stream()
    Zexray.Audio.close()
    Zexray.Window.close()

    :ok
  end

  defp next_frame do
    send(self(), :frame)
  end

  @impl true
  def handle_info(:frame, {wave, sound} = state) do
    # Detect window close button or ESC key
    if Zexray.Window.should_close?() do
      {:stop, :normal, state}
    else
      # Update

      {wave, sound} =
        if Zexray.Keyboard.pressed?(enum_keyboard_key(:space)) do
          if Zexray.Audio.recording?() do
            Zexray.Audio.stop_record()

            if not is_nil(sound) do
              sound
              |> Zexray.Audio.stop()
              |> Zexray.Resource.free()
            end

            sound =
              wave
              |> Zexray.Audio.load_sound_from_wave(:resource)
              |> Zexray.Audio.play()

            wave =
              type_wave(wave,
                frame_count: 0,
                data: []
              )

            {wave, sound}
          else
            Zexray.Audio.start_record()

            {wave, sound}
          end
        else
          {wave, sound}
        end

      # Draw

      Zexray.Drawing.with_drawing(fn ->
        Zexray.Drawing.clear_background(enum_color(:raywhite))

        text = if Zexray.Audio.recording?(), do: "STOP", else: "START"

        Zexray.Text.draw(
          "Press SPACE to #{text} recording the WAV sound!",
          150,
          180,
          20,
          enum_color(:lightgray)
        )
      end)

      next_frame()

      {:noreply, {wave, sound}}
    end
  end

  @impl true
  def handle_info({:audio_record_stream, wave_stream}, {wave, sound}) do
    type_wave(
      frame_count: data_frame_count,
      data: data
    ) = wave_stream

    type_wave(
      frame_count: wave_frame_count,
      data: wave_data
    ) = wave

    wave =
      type_wave(wave,
        frame_count: wave_frame_count + data_frame_count,
        data: wave_data ++ data
      )

    {:noreply, {wave, sound}}
  end
end
Example.start_link()