bbbradsmith / nsfplay

Nintendo NES sound file NSF music player
https://bbbradsmith.github.io/nsfplay/
277 stars 42 forks source link

nsf2flac,nsfmeta: Add tool for converting NSF[e] to FLAC, and a tool for fetching NSF[e] metadata as JSON. #50

Closed eatnumber1 closed 3 years ago

eatnumber1 commented 3 years ago

nsf2flac

The nsf2flac tool is little more than a bash script leveraging nsf2wav to convert the NSF to WAV, nsfmeta to extract the title, author, etc., jq to parse nsfmeta's output, and flac to encode the WAV as FLAC.

The general usage form for nsf2flac is:

Usage: nsf2flac file.nsf [track] [-- [flac flags] [-- nsf2wav flags]]

Meaning that the following invocation will convert track 1 of foo.nsf into foo.flac at the highest compression settings, with replaygain tagging, in mono, at a 96khz sample rate.

./nsf2flac foo.nsf \
    -- -o foo.flac --best --replay-gain --verify \
    -- --channels=1 --samplerate=96000

nsfmeta

Multi-track NSF[e] files should be supported, although I wasn't able to find any examples to test with.

Example use:

$ ./nsfmeta aibomb.nsf
[
    {
        "artist": "NARUTO",
        "copyright": "NARUTO",
        "title": "Artificial Intelligence Bomb"
    }
]

nsf2wav

Supporting the nsf2flac tool is also a few changes to nsf2wav:

eatnumber1 commented 3 years ago

@jprjr in case you want to take a look.

jprjr commented 3 years ago

A lot of NSF(e) files have 0xA9 bytes in the Copyright tag and assume the host system is using windows-1252 or iso-8859-1 encoding, so encoding to JSON throws an error since it's not a UTF-8 string. So now you've gotta deal with detecting what character encoding is in use, re-encoding it with libiconv or libicu or something, etc. This increases scope pretty significantly, because now you've gotta deal with character encoding, json encoding, etc, a lot of which doesn't have a lot to do with emulating an NES and producing audio.

For context, I wrote the nsf2wav utility to serve as more of a demo/guideline for how to use the library, like I pop that open in a separate text editor and follow along as I hack on plugins for music players. I didn't really intend for it to be the like, "official" method of converting NSF to WAV.

You'd probably be better served by tracking this in a separate repo and using nsfplay as a dependency, and building out a separate utility to perform nsf-to-flac.

eatnumber1 commented 3 years ago

I mean, under that same thinking the GUI code for Windows doesn't have a lot to do with emulating an NES producing audio either. Arguably, even with the encoding complexity some basic tools for working with NSFs are likely to be the most focused on the emulation, while leaving room to use those as building blocks for more complex use cases.

The library that the contrib directory provides is a usable C++ library, but isn't easy to build on for folks not familiar with C++. A common documented, low-level toolkit, of which nsf2wav is one part and something like nsfmeta is another, would make it easier for folks to work with nsfplay from any language by shelling out to the tools.

With this PR I'm somewhat testing the waters on what direction you and @bbbradsmith want to take this project, in that it is trying to provide a different kind of user experience for nsfplay. If you folks don't feel like you want that in this codebase, then I'll work on it in a separate repo as you suggested.

bbbradsmith commented 3 years ago

To be honest, I don't really have a stake in what's in the contribs folder.

My plans for NSFPlay are to finish up a few things for a final version 2 release, then begin a complete rewrite for version 3 (with more efficient overall structure, better separation between the core vs. gui, no more MFC or platform specific stuff except in separated platform specific libraries...).

So... I don't really know what the intended lifespan of these tools in contribs is going to be, but if either of you wants to maintain them, I'm fine to accept pull requests, but I'll defer to @jprjr for a decision on this pull request. As far as I can tell it looks OK? If there's no objection I would merge it.

As far as NSF/NSFe and chracter encoding... the official spec suggests UTF8 for NSF/NSFe going forward. In the past it had no spec, and there were multiple incompatible assumptions for character encodings, unfortunately. The plan for NSFPlay 3 is to use UTF8 by default, but have a couple of other options for displaying it in e.g. SHIFT-JIS, or trying to autodetect. For what to do in this tool, that's up to you, but converting an $A9 copyright symbol to UTF8 doesn't sound like a big issue?

jprjr commented 3 years ago

If you're OK with it, I'm OK with it, my main concern was around scope.

eatnumber1 commented 3 years ago

Huh, for a library with basically one function, iconv turns out to be surprisingly tricky to get right.

Nevertheless, my latest commit does the character encoding to UTF-8 based on a flag option. I opted not to try and do any auto-detection, since the modern NSF[e] standard calls for UTF-8 and generalized encoding detection is heuristic at best.

eatnumber1 commented 3 years ago

Hey @bbbradsmith, friendly ping. I think that this is ready to merge, if it looks okay to you.

bbbradsmith commented 3 years ago

@eatnumber1 It's on my radar. I was not able to find time last weekend to look at it, but I will try to get to it this weekend.