NetMD

Drive Sony MiniDisc recorders over NetMD USB from Elixir. A port of netmd-js (the library behind Web MiniDisc) cross-referenced against libnetmd from linux-minidisc, running on bodge_usb. Linux only, no native code beyond the bodge_usb NIF.

Implemented mostly using LLM. But proven on hardware and made with some care. A port of the awesome C and JS/TS work that's been done already.

What works

Tested hardware

Confirmed working on a Sony MZ-N707. The other ~48 devices in the table are wired up by USB id and protocol but have not each been exercised on hardware.

Usage

# See every connected NetMD before picking one to open.
for d <- NetMD.list_devices(), do: IO.puts("#{d.name} on bus #{d.bus}/#{d.address}")
{:ok, device} = NetMD.open()
{:ok, disc} = NetMD.list_content(device)
IO.puts("#{disc.title}: #{disc.track_count} tracks")
:ok = NetMD.play(device)
:ok = NetMD.rename_disc(device, "Mix Tape")
# Download audio: raw PCM (16-bit big-endian stereo, 44100 Hz) or
# pre-encoded ATRAC3 for the LP modes.
track = %NetMD.Track{title: "New Song", format: :lp2, data: atrac3_data}
{:ok, %{track: n}} = NetMD.download(device, track)
NetMD.close(device)

The facade delegates to layers that are usable on their own; see the module docs of NetMD.Commands, NetMD.Interface, NetMD.Session, NetMD.Device, NetMD.Query and NetMD.Factory.

Running without hardware

NetMD.Simulator is a virtual NetMD device that decodes the protocol and holds disc state, so the whole library runs in-process with no USB:

{:ok, device} = NetMD.open(transport: NetMD.Simulator)
{:ok, disc} = NetMD.list_content(device)

To exercise the real usbfs transport too, NetMD.Simulator.Gadget presents that same brain as an actual USB device over FunctionFS; with dummy_hcd it and a host driving NetMD.Transport.Usb run in one VM. See vm/README.md.

Permissions

Accessing /dev/bus/usb needs root or a udev rule for your user, e.g.

SUBSYSTEM=="usb", ATTRS{idVendor}=="054c", MODE="0666"

Testing

The protocol layers are verified byte-for-byte against golden vectors generated from netmd-js itself, and the full flows replay against a scripted mock transport. See TESTING.md.

Installation

def deps do
[
{:netmd, github: "lawik/netmd"}
]
end

License

GPL-2.0, matching the reference implementations this library ports.