/linux-minidisc

Free software for accessing MiniDisc devices

Primary LanguageCGNU General Public License v2.0GPL-2.0

minidisc-ffwd: friendly fork, wip development

A friendly fork of linux-minidisc to more freely experiment with things with less friction while eventually getting most changes merged back into the upstream repository.

Upstream repos and relationships:

    (o) Original Upstream Repo ("upstream")
     |  https://github.com/linux-minidisc/linux-minidisc
     |
    (o) NetMD fixes by vuori (upstream PR#62)
     |  https://github.com/vuori/linux-minidisc
     |
    (o) Downstream repo w/ fixes, used by Platium MD (upstream PR#82)
     |  https://github.com/gavinbenda/linux-minidisc
     |
  > (o) This Repo
     |  https://github.com/thp/linux-minidisc
     |
     v

Ideally all those changes will eventually find their way back into the upstream repo, but for now, this faster-moving branch is where it's at.

README of the vuori fork is here. Original README of upstream is here.

NetMD Download Support for QHiMDTransfer

Now that netmd_send_track() exists in libnetmd, we can call it from QHiMDTransfer to download tracks to the device. This accepts the same file formats as Platinum MD, namely 44.1 kHz 16-bit stereo WAV files for SP download or ATRAC LP2/LP4 data stored in a WAV container for direct LP2/LP4 download.

Track Duration Fix

libnetmd returned the wrong duration for tracks > 1 hour, because the "hour" item of the response wasn't take into account (so e.g. a 68-minute track would show up as an 8-minute track). This is fixed now, and the struct netmd_track's minute can now be >= 60.

Meson Build System

There is now support for the Meson Build System, which is a bit more flexible and modern than the old qmake (for libs, CLI).

Care was taken so that the old qmake-based system still works if needed.

Building with Meson is simple, it always builds out-of-source-tree (here, build is used as the build folder, and ninja is the build system):

meson build
ninja -C build

To build libnetmd and libhimd as static libraries (e.g. so that netmdcli and himdcli can be used standalone):

meson build -Ddefault_library=static
ninja -C build

As part of this modification, the libnetmd public headers do not depend on libusb.h directly anymore, which helps keep things modular.

The build dependencies are now much cleaner, and Meson's dependency system is used, which on Linux uses pkg-config for everything by default, which works fine on modern distros.

Linux NetMD Permissions

The udev rules file for Linux (so users in the "plugdev" group will have access to NetMD devices without requiring root) is now installed in the right place automatically when using the Meson build system.

The HAL file (netmd/etc/20-netmd.fdi) was removed without replacement, as HAL is deprecated in Linux for more than 10 years now.

libusbmd: Central VID/PID database

A new library "libusbmd" contains the central database for both NetMD and Hi-MD USB device IDs. It provides a simple C API for querying all entries as well as identifying a device given a VID and PID.

The CLI tools (netmdcli and himdcli) now each have a usbids sub-command that will query libusbmd for the specific device IDs and output them as JSON (VID and PID as decimal, as JSON doesn't support hex literals).

QHiMDTransfer now also uses libusbmd for identifying devices.

The database is embedded in libusbmd and generated from devicedb/minidisc.devids.

JSON output format string vulnerability

When outputting the track list for both netmdcli and himdcli, there was a format string vulnerability, as the JSON output was the format string passed to printf(). Titling a track with special printf commands (%s, %n, ...) would result in a crash or worse.

Removal of qmake support

The meson.build file now has support for building the Qt5 GUI, so we can remove all the qmake-related cruft. By default the GUI building is disabled, but you can enable it with:

meson build -Dwith_gui=true
ninja -C build
build/qhimdtransfer

Some things might have been broken during the build system transition, let me know and we can look into fixing it up.

Proper device type detection in QHiMDTransfer

Use the device type provided by libusbmd for detection of devices instead of relying on the string "NetMD" appearing in the device name.

Nicer command-line handling for netmdcli

More structured command-line handling and better argument parsing / error reporting for netmdcli has been implemented. Some commands weren't visible in the help text, these have now been added. The JSON track list has been renamed to the json sub-command, and by default, the help message is printed. The CLI discinfo command now shows the text-only disc info (like before the JSON changes).

Right now the commands have mostly been implemented in a backwards-compatible manner, in the future it might make sense to shuffle around and rename some commands.

Cleaned out obsolete files in libnetmd

The files CHANGELOG, hotplug-netmd and minidisc.usermap were not used/updated in a long time. They can always be inspected from Git history if needed.

Progress information callbacks in libnetmd for downloading tracks

Added netmd_send_progress_func to libnetmd's send-related functions that (if not NULL) will call back with progress information, so the user interface can show info about the current progress to the user. This is used by netmdcli and QHiMDTransfer.

Consistent zero-based index for netmdcli recv

The netmdcli recv function now interprets the track ID as zero-based to be consistent with other calls that take a zero-based track ID. This change also applies to the netmd_secure_recv_track() function, which previously took a 1-based track ID.

Utility function netmd_dev_can_upload()

Instead of hardcoding string comparisons with "Sony MZ-RH1 (NetMD)", add a utility function that can query whether or not a NetMD-capable device can upload. Right now, this is restricted to the MZ-RH1 only, but allows for more semantic features in the future.

Automatic filename generation in netmdcli recv

The filename parameter to netmdcli recv is now optional. If not supplied, a filename will be generated based on the track title (or number if the title is empty) and file type (.aea for SP-mode tracks, .wav for LP2/LP4-mode tracks).

Progress information callbacks in libnetmd for uploading tracks

Similar to the track downloading progress, libnetmd now also has support for a netmd_recv_progress_func callback. This is used by netmdcli and QHiMDTransfer.

This also removes the duplicated libnetmd-based code that was in QHiMDTransfer.

Add enum types and remove find_pair() API for converting values to strings

Add enums NetMDEncoding, NetMDTrackFlags and NetMDChannels. Add functions netmd_get_encoding_name() and netmd_track_flags_to_string(). Remove the old find_pair() APIs that were used for this purpose before.

netmd_get_track_info() convenience method and struct

In many cases, a caller wants to retrieve all the information for a track (name, duration, format) at once, as well as e.g. strip the "LP:" prefix of a track.

This is now possible using a new struct and function to query the track info all at once. The struct that is filled also has proper enum types, and takes care of storing the title string, so it's all nice and tidy in a single place.

Better handling of the minidisc struct (groups and disc name)

Added netmd_minidisc_*() functions to query disc name, group membership of a track, group name and whether a group is empty or not. This again combines logic that existed twice in netmdcli and QHiMDTransfer for some time.

More intelligent "LP:" prefix stripping

MDLP recorders prefix LP2/LP4 recordings with "LP:" in the title, which is shown on non-MDLP recorders. Instead of stripping a leading "LP:" unconditionally, only strip it for LP2/LP4 tracks. This allows SP tracks to begin with "LP:" if needed.

Unified formatting of track and disc time durations

Instead of doing custom formatting in multiple places and accessing the structs, netmd_track_duration_to_string() and netmd_time_to_string() are now available that format a custom structure into a C string. The returned string can be free'd with netmd_free_string().

Redesigned discinfo output (with ANSI colors) for netmdcli

The disc information sub-command of netmdcli has been overhauled and now features fancy ANSI colors (can be disabled with -n, and will be automatically disabled if standard output is not a TTY, e.g. if you pipe the output into less).

Cleaned up CI scripts, Github Actions

The CI scripts now live in scripts/ instead of build/. Travis CI support has been removed, and replaced with Github Actions. The CI scripts have been simplified.

Removed libnetmd_extended.h header

This was used by QHiMDTransfer's copies of internal functions, but since we have now moved those back into the library, there's no need to expose those details.

Moved non-source files out of libnetmd into docs (or deleted)

The libnetmd folder contained lots of non-source files, move those to docs/. Some files were deleted:

  • libnetmd/documentation/index_files: No useful content
  • libnetmd/LICENCE.TXT: Older version of the GPL2, already exists as COPYING
  • Moved README.vuori and README.fedora to docs/
  • .cdtproject, .project, Doxyfile: Deleted

Whole-project Doxygen tooling

You can run doxygen in the project root to get browsable documentation (for the most part).

Remove netmd_write_track() in favor of netmd_send_track()

The old function wasn't used/tested, and the new function is.

Combine the two time/duration structs in libnetmd

Instead of having two slightly incompatible structs for the same thing, have only a single netmd_time data type used for both the track length and disc capacity.

ANSI Colors in netmdcli on Windows

For Windows 10 v1511 and newer, special code has been added to enable support for ANSI colors in conhost.exe / cmd.exe. The Windows Terminal already supports ANSI escape sequences out of the box (for the discinfo color output).

Removal of netmd_get_devname()

Instead of accessing the generic USB device name (e.g. "Net MD Walkman"), the device_name member of struct netmd_device (returned by netmd_init()) should be used instead, which contains proper model names from libusbmd.

Reworked group handling code

The previous group handling code was buggy and hard to maintain. Reworked most of the code in a new module groups.c based on the existing handling code. Removed some hard-to-get-right commands (group, groupmove) in netmdcli and replaced them with a new group command that just specifies the range, and will bail out if the new group would overlap with existing groups.

More could be done in this area, and deleting and moving tracks does not yet interact with the group code, but it's already better than before.

As a side effect of this change, netmd_get_track_count() has been added based on code from libnetmd.py and netmd-js.

1-based indexes for netmdcli

To make group-related features less confusing, the user-facing part of netmdcli now deals with 1-based track indexes. The library libnetmd itself usually deals with zero-based track IDs. The groups code is slightly different, because zero has a special meaning for groups.

Split out upload-related functions to smaller pieces for easier reuse

New functions for libnetmd/recv.h for filename generation and file extensions. Also, netmdcli's recv can now transfer all the files at once by not passing in the track ID, this allows netmdcli recv to upload the whole disc in one go.

"Backport" the formatQuery / scanQuery functions from libnetmd.py / netmd-js

In order to easily port things from libnetmd.py and netmd-js, its format string- based request/response methods are now available in libnetmd using the new netmd_format_query() and netmd_scan_query() functions, adopted slightly to be more C-like compared to the Python and JavaScript implementations. The netmd_get_track_count() function is the first one to use this new feature.

netmdcli uuid <track_id>

Add support for querying and printing the UUID of a track via netmdcli. This also introduces the netmd_uuid type, netmd_uuid_to_string() function and an updated netmd_secure_get_track_uuid(), making use of new typedefs and query.

Expanded descriptor state handling (descriptor.h / descriptor.c)

Moved the descriptor state handling into its own module within libnetmd. The code is baed on from asivery's AV/C improvements to netmd-js.

Query formatting and scanning: Support for 8-bit and 16-bit BCD

The query formatting and scanning gets two new escapes: %B and %W for writing and reading 2-digit and 4-digit BCD values directly, avoiding the need to convert BCD explicitly before/after.

Merge netmd_get_current_track() into netmd_get_playback_position()

Those two functions use the same underlying query, so it makes sense to combine them, so that only a single query is done. Also backported the descriptor state changes from netmd-js for the playback position query.

Hook up "Help" action in QHiMDTransfer

The QHiMDTransfer app does have a help button in the toolbar and in the menu, but it didn't do anything. Hook it up and for now, open the Github page of this fork in the system web browser.

Initial cleanup of QHiMDTransfer

Instead of having a two-pane browser and some redundant information, only have a single-pane view, and handle upload and download file selection via dialogs and toolbar/menu items. Some menu items (e.g. "Rename" and "Delete") were never working, so hook them up for now and show a message until we implement it.

Other initial fixes to the UI and code of QHiMDTransfer, check the diff.

Formatting of NetMD discs is now possible from the QHiMDTransfer GUI, and the write-protect status can be queried with netmd_is_disc_writable() (the GUI takes care of disabling write features if the disc is write-protected).

Group information moved into netmd_dev_handle

Because certain operations need to update group information, it makes sense that group information is treated as part of the NetMD device handle. This should allow for easy invalidation and update of group information.

netmdcli: set-raw-title, get-raw-title and settitle

Now that the group information handling has been merged into the device handle, settitle can just set the normal title without affecting the groups. For advanced use cases, the user can still set and get the raw title.

contrib/netmd-send-file: Send any file format to a NetMD recorder

Similar to what Platinum MD and netmd-js are doing, this script combines ffmpeg, atracdenc and netmdcli to send SP/LP2/LP4 to a NetMD unit.

ATRAC3 encoding using atrac3.acm

As an optional tool, contrib/atracenc contains code for a small CLI tool that can use the closed atrac3.acm file to convert a PCM WAV file into an ATRAC3 LP2/LP4 WAV file that can be used with netmdcli send.

Fix crash on macOS shutdown

The QHiMDMacDetection class had code in its destructor that was already present in its superclass destructor. As the superclass destructor is run anyway, this duplicate code caused the app to crash (double free, etc...).

Hi-MD track metadata editor for QHiMDTransfer

The GUI got a new GUI for editing the Hi-MD track metadata (title, artist, album). While the UI is fully functional, saving isn't implemented yet.

himd/himd.py: Dump the track index in text form

For debugging and experimenting, this script based on libhimd can be used to dump all parts of the track index file.

libhimd: Add himd_track_set_string() and helper functions

This allows updating metadata on Hi-MDs. Also, himd_remove_string() and himd_update_track_info() have been added (and are used by it). To write the changes to disk, himd_write_tifdata() should be called afterwards.

The editing of track/artist/album in Hi-MDs is implemented in QHiMDTransfer.

Hi-MD MP3 downloading: Fall back to file basename for files without tags

Instead of uploading an "empty" title, take the file basename as a title for MP3 downloads to Hi-MD media. With the new edit function, the user can then easily edit the track metadata in QHiMDTransfer.

Download dialog with progress for QHiMDTransfer

Re-purpose the upload dialog for download progress information. For NetMD, download progress is quite fine-grained, for Hi-MD (MP3 download), it also works, but the granularity is on the level of files due to missing progress callbacks.

Support for disc title and groups in libhimd

Add himd_get_group_info() and himd_get_disc_title() functions to libhimd. Display Hi-MD disc title in QHiMDTransfer, groups not exposed in GUI yet.

macOS mountpoint detection for QHiMDTransfer

Detect mount points via DiskArbitration.

QHiMDTransfer: Show recorded data and available space for Hi-MD

Provide total track duration, number of tracks and disk usage, as well as available free space, and estimated recording time for MP3 files (as these are the only file types we can currenty "download" to Hi-MD media).

QHiMDTransfer: Implement track deletion for NetMD devices

Deleting of selected tracks is now supported for NetMD devices in the GUI. Tracks on Hi-MD devices cannot be deleted yet.

QHiMDTransfer: Upload of MP3 files to NetMD using ffmpeg

Quick'n'dirty implementation of MP3 file upload to NetMD by using ffmpeg (the command-line tool) to decode the MP3 to a temporary PCM file.

Fix polling/monitoring of new USB devices

The polling of USB devices was broken (at least with recent Qt versions). Fix this by starting the timer in the main thread, and hooking up timer events in the background (polling) thread.

QHiMDTransfer: Playback controls for NetMD devices

Added a UI to QHiMDTransfer that allows controlling playback and showing the current playback position for NetMD devices (audio output happens on the NetMD device).

Remove id3tag dependency from libhimd

The himd_writemp3() now takes title, artist and album strings as parameters (can be NULL) so the caller can set those items. This removes the dependency on libid3tag. For himdcli, the user can specify those values on the command line. For QHiMDTransfer, the existing dependency of TagLib (which was used for writing tags of uploaded MP3 files) is now also used for retrieving metadata when downloading MP3 files to Hi-MD.

QHiMDTransfer: Carry out downloads, uploads and refresh in background task

This avoids blocking the UI, making sure it's always responsible, even if the background task is blocking. Communication from background task to the UI thread happens via Qt signals/slots.