Current section
Files
Jump to
Current section
Files
lib/netmd.ex
defmodule NetMD do
@moduledoc """
Drive MiniDisc recorders over NetMD USB.
A port of the NetMD protocol as implemented by netmd-js and libnetmd
(linux-minidisc), on top of `BodgeUSB`.
{:ok, device} = NetMD.open()
{:ok, disc} = NetMD.list_content(device)
:ok = NetMD.play(device)
track = %NetMD.Track{title: "New Song", format: :lp2, data: atrac3_data}
{:ok, %{track: n}} = NetMD.download(device, track)
This module is a convenience facade; the layers underneath are usable
on their own:
* `NetMD.Commands` - disc listing, renaming, transfers
* `NetMD.Interface` - the full NetMD command set
* `NetMD.Session` / `NetMD.Track` - secure download sessions
* `NetMD.Device` - the raw USB exchange protocol
* `NetMD.Query` - the query format/scan DSL
"""
alias NetMD.Commands
alias NetMD.Device
alias NetMD.Interface
@doc "List all connected NetMD devices. See `NetMD.Device.list/1`."
@spec list_devices(keyword()) :: [Device.listing()]
defdelegate list_devices(opts \\ []), to: Device, as: :list
@doc "Open the first NetMD device found. See `NetMD.Device.open/1`."
@spec open(keyword()) :: {:ok, Device.t()} | {:error, term()}
defdelegate open(opts \\ []), to: Device
@doc "Close the device."
@spec close(Device.t()) :: :ok
defdelegate close(device), to: Device
@doc """
Subscribe to `{:netmd_status, status}` change events from the background
poller. See `NetMD.Device.subscribe/2`.
"""
@spec subscribe(Device.t(), pid()) :: :ok | {:error, :status_events_unavailable}
defdelegate subscribe(device, pid \\ self()), to: Device
@doc "Stop receiving status events. See `NetMD.Device.unsubscribe/2`."
@spec unsubscribe(Device.t(), pid()) :: :ok | {:error, :status_events_unavailable}
defdelegate unsubscribe(device, pid \\ self()), to: Device
@doc "Device state (disc presence, playback state, position)."
@spec device_status(Device.t()) :: {:ok, map()} | {:error, term()}
defdelegate device_status(device), to: Commands
@doc "Full disc listing. See `NetMD.Commands.list_content/1`."
@spec list_content(Device.t()) :: {:ok, NetMD.Disc.t()} | {:error, term()}
defdelegate list_content(device), to: Commands
@doc "Start playback."
@spec play(Device.t()) :: :ok | {:error, term()}
defdelegate play(device), to: Interface
@doc "Pause playback."
@spec pause(Device.t()) :: :ok | {:error, term()}
defdelegate pause(device), to: Interface
@doc "Stop playback."
@spec stop(Device.t()) :: :ok
defdelegate stop(device), to: Interface
@doc "Fast-forward."
@spec fast_forward(Device.t()) :: :ok | {:error, term()}
defdelegate fast_forward(device), to: Interface
@doc "Rewind."
@spec rewind(Device.t()) :: :ok | {:error, term()}
defdelegate rewind(device), to: Interface
@doc "Skip to the next track."
@spec next_track(Device.t()) :: :ok | {:error, term()}
defdelegate next_track(device), to: Interface
@doc "Skip to the previous track."
@spec previous_track(Device.t()) :: :ok | {:error, term()}
defdelegate previous_track(device), to: Interface
@doc "Restart the current track."
@spec restart_track(Device.t()) :: :ok | {:error, term()}
defdelegate restart_track(device), to: Interface
@doc "Seek to a track (zero-based)."
@spec goto_track(Device.t(), non_neg_integer()) ::
{:ok, non_neg_integer()} | {:error, term()}
defdelegate goto_track(device, track), to: Interface
@doc "Seek to a time within a track. See `NetMD.Interface.goto_time/3`."
@spec goto_time(Device.t(), non_neg_integer(), keyword()) :: :ok | {:error, term()}
defdelegate goto_time(device, track, opts \\ []), to: Interface
@doc "Eject the disc."
@spec eject_disc(Device.t()) :: :ok | {:error, term()}
defdelegate eject_disc(device), to: Interface
@doc "Erase the whole disc."
@spec erase_disc(Device.t()) :: :ok | {:error, term()}
defdelegate erase_disc(device), to: Interface
@doc "Erase a track (zero-based)."
@spec erase_track(Device.t(), non_neg_integer()) :: :ok | {:error, term()}
defdelegate erase_track(device, track), to: Interface
@doc "Move a track (both positions zero-based)."
@spec move_track(Device.t(), non_neg_integer(), non_neg_integer()) ::
:ok | {:error, term()}
defdelegate move_track(device, source, dest), to: Interface
@doc "Rename the disc, preserving groups. See `NetMD.Commands.rename_disc/3`."
@spec rename_disc(Device.t(), String.t(), keyword()) :: :ok | {:error, term()}
defdelegate rename_disc(device, name, opts \\ []), to: Commands
@doc "Rename a track (zero-based)."
@spec rename_track(Device.t(), non_neg_integer(), String.t(), keyword()) ::
:ok | {:error, term()}
defdelegate rename_track(device, track, title, opts \\ []),
to: Interface,
as: :set_track_title
@doc "Download a track to the disc. See `NetMD.Commands.download/3`."
@spec download(Device.t(), NetMD.Track.t(), keyword()) :: {:ok, map()} | {:error, term()}
defdelegate download(device, track, opts \\ []), to: Commands
@doc "Upload a track from the disc (MZ-RH1 only). See `NetMD.Commands.upload/3`."
@spec upload(Device.t(), non_neg_integer(), keyword()) :: {:ok, map()} | {:error, term()}
defdelegate upload(device, track, opts \\ []), to: Commands
@doc """
Enter factory mode for direct memory access and patching. Dangerous;
see `NetMD.Factory`.
"""
@spec factory(Device.t()) :: {:ok, NetMD.Factory.t()} | {:error, term()}
defdelegate factory(device), to: NetMD.Factory, as: :open
end