0 users browsing Projects. | 1 guest  
Main » Projects » NSF/SPC to MIDI automated converter project
Pages: 1
Posted on 18-12-01, 17:20
Post: #1 of 7
Since: 12-01-18

Last post: 682 days
Last view: 674 days
Just thought I'd announce that I'm starting to work on a standalone NSF/SPC player based on higan source code.

For those curious to watch my progress, I'm hosting the code on https://github.com/JamesDunne/vgm2midi

Obviously, no warantee nor guarantee of functionality here. It's just a very early work in progress.

Once compiled, it produces a console application that emits a WAV file given an input NSF file passed as a commandline argument, if it works at all. It's woefully incomplete and doesn't play most NSFs at the moment. I'm currently working on creating a custom cartridge Board (aka mapper) implementation of the custom iNES mapper 031 to better support NSFs since most seem to require/expect it.

This project is actually more of a stepping stone to my ultimate goal of writing an NSF (and SPC) to MIDI converter. The first milestone is to get a working NSF player, or more simply an NSF to WAV converter. After that I'll augment the APU code to do the MIDI conversion work.

I've actually already prototyped out my NSF/SPC to MIDI converter project based on libgme sources. However, its lack of emulation accuracy was causing issues that couldn't easily be resolved without an impossibly large refactoring or rewrite due to the way it emulates the systems. You can find that effort here: https://github.com/JamesDunne/libgme

NSF is fairly trivial to convert to MIDI because the melodic channels (pulse and triangle) all provide absolute pitch information, so simply taking the log2(pitch / 55.0) * 12 + 36 yields a standard MIDI note number representing the pitch, largely solving the problem. After that you can do more nuanced heuristics to support pitch wheel changes, channel changes, patch changes, etc. It's a fun problem to solve iteratively and listen to your results as the process evolves to produce better and better sounding results.

SPC poses a little bit more of a challenge to convert to MIDI than does NSF. The primary reason being that the SPC is just 8 channels of digital samplers, and the instruments sampled are basically PCM waveforms (after decoding from BRR). The reason this poses a challenge is because the SPC's pitch registers only provide a relative-pitch resampling of the original sample (-2 oct to +2 oct, and lots of semitones in between); there is no absolute pitch information readily available to the SPC. One would have to somehow "know" the absolute pitch of the recorded sample. In practice, there is no "standard" pitch at which to sample an instrument so no real assumption can be made that would cover all samples.

I've had very good success with identifying the fundamental pitch of a PCM sampled instrument by running an FFT (Fast Fourier Transform) over its looped section and using some heuristics to identify the lowest-pitched highest peak which I presume to be the fundamental pitch of the instrument. If one naively grabs simply the highest peak you will get some false-positives due to some instruments having stronger overtones present over the fundamental pitch (like trumpets).

This works great for melodic instruments like strings, piano, guitar, horns, etc. but does not work at all for percussive instruments like drums: kick, snare, hi-hat, drum loops, etc.

To solve this general problem, I've opted to allow the end user to supply a custom mapping file that specifies what exact MIDI representation to use for each sample, including which MIDI program numbers to use, a transposition amount in semitones to adjust for having the wrong octave or erroneously detecting an overtone instead of the fundamental pitch, and even an optional mapping to the General MIDI percussion channel 10 specific notes for samples like kick, snare, hi-hat, crash, bongos, toms, etc. No support for drum loops (think Jurassic Park soundtrack) yet but it does sound feasible to emit a MIDI drum loop every time a sample of a drum loop is seen. It'd just be very difficult to encode such a MIDI drum loop in a mapping file.

All of that MIDI conversion effort is present in my libgme fork but I'm stopping work there so I can get a much more stable/accurate emulation base with higan sources. Once I get a basic NSF and SPC player going, I can port over my MIDI conversion work to higan and pick up where I left off.
Posted on 18-12-02, 00:39

Post: #9 of 49
Since: 10-29-18

Last post: 407 days
Last view: 292 days
FWIW, Kode54 maintains an updated version of GME within his various audio projects like foo_gep and Cog.app. I don't remember which service he prefers to host on, though, but I'm 95% sure there's a link to the foo_gep source on the foo_gep page on Foobar2000's site.
Posted on 18-12-03, 00:33
Post: #2 of 7
Since: 12-01-18

Last post: 682 days
Last view: 674 days
I now have a working NSF player that supports both bank-switched and non-bank-switched NSFs. NSF file and track may be selected by command line argument.

https://github.com/JamesDunne/vgm2midi

Next milestone is an SPC player which looks not too difficult to implement.
Posted on 18-12-04, 16:19
Post: #3 of 7
Since: 12-01-18

Last post: 682 days
Last view: 674 days
I've hit a snag in my SPC player. Can anyone help me out here?

I've set up the emulator to disable the SNES CPU and PPU, leaving only the SMP and DSP running. I load up the SPC RAM and registers and the DSP registers from the SPC file and start the emulator but I only get the first note/chord of music and then the instruments just ring out and no further music is played. I think the SPC700 is waiting on something to continue but I'm not sure what.
Posted on 18-12-05, 05:53
Post: #9 of 173
Since: 11-01-18

Last post: 7 days
Last view: 1 hour
its waiting on the CPU.
Posted on 18-12-05, 11:21

Post: #44 of 210
Since: 10-29-18

Last post: 382 days
Last view: 354 days
Yup. Two timing crystals.
Posted on 18-12-05, 23:54
Post: #4 of 7
Since: 12-01-18

Last post: 682 days
Last view: 674 days
Any idea what in particular it's waiting for from the cpu? I was fairly certain I wouldn't have to emulate the cpu for a SPC player.

Maybe I just need to emulate the cpu responses or write-back? SPC player documentation is nearly non-existent. The file spec is documented but the emulation process and semantics are not.
Posted on 18-12-06, 00:03
Post: #5 of 7
Since: 12-01-18

Last post: 682 days
Last view: 674 days
Can you elaborate on "two timing crystals"? I realize the SPC and cpu run at different rates and are largely independent except for the communication registers. The SPC emulation treats them as ram when written to and read from. The cpu can of course write to them as well. Is there an implied tiny cpu support program I need to emulate that responds to certain SPC requests?
Posted on 18-12-06, 05:27
Post: #10 of 173
Since: 11-01-18

Last post: 7 days
Last view: 1 hour
in rough strokes, the SPC is an instrument played by the CPU.
Posted on 18-12-06, 06:56
Full mod

Post: #52 of 420
Since: 10-30-18

Last post: 26 days
Last view: 19 hours
But the SPC file-format only provides initial registers and RAM content for the SPC, it doesn't give the CPU anything to do. So what should an SPC-player do?

The ending of the words is ALMSIVI.
Posted on 18-12-06, 07:21

Post: #29 of 299
Since: 10-29-18

Last post: 3 days
Last view: 1 hour
Posted by jsd1982
I've set up the emulator to disable the SNES CPU and PPU, leaving only the SMP and DSP running. I load up the SPC RAM and registers and the DSP registers from the SPC file and start the emulator but I only get the first note/chord of music and then the instruments just ring out and no further music is played. I think the SPC700 is waiting on something to continue but I'm not sure what.

From what game is the SPC file? Tried others?

My current setup: Super Famicom ("2/1/3" SNS-CPU-1CHIP-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Posted on 18-12-06, 07:25
Post: #41 of 375
Since: 10-30-18

Last post: 12 days
Last view: 2 hours
Afaik although the SPU does not need continual guidance from the CPU (unlike on the NES?) it still needs the CPU to tell it to begin playback and when to switch songs etc.

AMD Ryzen 3700X | MSI Gamer Geforce 1070Ti 8GB | 16GB 3600MHz DDR4 RAM | ASUS Crosshair VIII Hero (WiFi) Motherboard | Windows 10 x64
Posted on 18-12-06, 13:04
Post: #6 of 7
Since: 12-01-18

Last post: 682 days
Last view: 674 days
Exactly. The SPC file format only includes the state of the SPC and DSP. I've loaded in the SPC registers PC, A, X, Y, P, and S. Also loaded in the 128 DSP registers for voice control and others.

My test SPC tracks include f-zero, jurassic park, zelda 3. Every SPC I've tried exhibits this behavior of just stopping after the first chord, so it must be something I'm missing in my player.

The DSP sounds right, since the instruments sound correct and ring out, so the problem must be in the SPC side. I've got the IPL ROM loaded in, and I've tried both both the IPL from higan/bsnes and the 64 bytes at the end of the SPC file. Neither affect the outcome differently.
Posted on 18-12-07, 21:27
Post: #7 of 7
Since: 12-01-18

Last post: 682 days
Last view: 674 days
Finally, a working SPC player!

I found some code from bsnes-plus which is able to plays SPCs and was able to get my code working. I think the key was initializing the SMP and DSP internal registers.
Posted on 18-12-08, 00:53
Custom title here

Post: #113 of 941
Since: 10-30-18

Last post: 2 days
Last view: 19 hours
Hooray!

--- In UTF-16, where available. ---
Posted on 18-12-09, 15:42

Post: #45 of 210
Since: 10-29-18

Last post: 382 days
Last view: 354 days
What happened to that new format that replaced SPC?
Posted on 18-12-09, 18:20

Post: #32 of 299
Since: 10-29-18

Last post: 3 days
Last view: 1 hour
There's SNSF, though I'm not sure if byuu or someone else didn't release another format (recording all the data that is sent over the CPU->APU interface?).

My current setup: Super Famicom ("2/1/3" SNS-CPU-1CHIP-02) → SCART → OSSC → StarTech USB3HDCAP → AmaRecTV 3.10
Posted on 18-12-09, 21:55 (revision 1)

Post: #7 of 33
Since: 10-29-18

Last post: 88 days
Last view: 88 days
There was SFM, however:
Posted by byuu
we got bogged down because a true state capture has internal variables, and different emulators will want to name those fields differently (they definitely don't have official names.) Some emulators won't even support certain state fields, others may require new ones not yet known for a perfect capture. Forking the format with emulator-specific sections is the worst possible thing you can do.

Oh, well...
Pages: 1
Main » Projects » NSF/SPC to MIDI automated converter project
Yes, it's an ad.