NSFPlay 2.1

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
NSFPlay 2.1
by on (#91896)
I have begun to maintain NSFPlay/NSFPlug, and a new version is ready. If anyone is interested in an updated version it is available here:

http://rainwarrior.ca/projects/nsfplay/


Version history:

NSFPlay 2.1 - 3/27/2012
Audio Output:
- Fixed race condition in audio buffering; stand alone NSFPlay would occasionally get stuck stuttering.
- Produces stereo output, channel mixer dialog for panning and per-channel volume control.
- Fixed PCM playback speed; CPU execution was counting requested clocks, not clocks executed.
- Fixed accuracy of seek times.
- Loop detection now accounts for all audio registers, not just a subset of 2A03 and N163.
- N163 wavelength is actually 6-bit, not 3. Now allows sample length up to 256.
- Fixed FDS volume/sweep envelope caps. (Direct register writes can make them louder.)
- Fixed FDS modulation bias calculation and wrapping.
- Set default volume for VRC7 and FDS a little lower (to match expected levels).
- MMC5 PCM support (for both read and write mode).
- Added phase reset option to MMC5.
- MMC5 was missing length counter and audio register reads; rewrote to conform with APU.
- Adjusted phases for APU/MMC5 square channels to match NesDev's description.
- APU/DMC/MMC5 rewrite of envelope/length/sweep behaviour to use a frame sequencer instead of independent timers.
Options:
- Option to randomize noise on reset (on by default).
- Options cleanup, removed unused/deprecated options from .ini file.
- Using global LPF by default instead of on each device (saves CPU, same result).
- Keyboard view channel colour is now customizable in .ini file (CHANNEL_XX_COL).
Keyboard view:
- Fixed crash due to keyboard OnTimer being allowed before Reset() is executed by the PlayThread.
- Double buffering keyboard view to remove flicker.
- Different colours for different expansions in keyboard view.
- Fixed sound lag after seek.
- FME-7 now named 5B, N106 now named N163.
- DPCM now named DMC in keyboard view.
- Fixed 5B volume display (E now correctly indicates envelope, volume is now correct value).
- 5B now displays envelope and noise.
- VRC6 saw volume now displays accumulator register.
- Corrected VRC6 saw pitch in keyboard view.
- Fixed trailing lines on N163 waveform display.
- DMC volume display no longer flipped (is now $4011 register value).
- DMC now shows sample frequency rather than byte frequency.
- Triangle and noise were not showing muting due to length counter of 0.
- Noise now has frequency display (either rate of random samples, or tonal frequency for periodic noise).
- Removed feature that extends the life of key dots beyond the frame the channel is active (frequency can change when key is silent, esp. VRC6 squares, which visibly jump to the wrong pitch)
Other:
- Save WAV button on NSFPlay.
- Command line WAV output for batch processing.
- Added extra NSF header information to "misc" text box, initial banks, load/init/play addresses, etc.
- Fixed thread-safety issue for configuration (was accessed liberally from many threads).
- Removed legacy code for windows versions older than XP.


NSFPlay 2.0 - 2/22/2012
- Restructured sln/vcproj files, and rebuilt for VS9.
- All intermediate files go into common Debug/Release directories.
- Renamed wa2nsf project to in_yansf to match name of the plugin.
- Fixed improperly set WAVEFORMATEX header in libemuwa2 (allows execution on windows Vista/7).
- Corrected pitch of noise channel.
- Updated VRC7 default patch set.
- Added PAL support and pal flags indicator (PREFER_PAL=1 to prefer PAL for dual mode).
- Added about box for determining build version.
- Fixed some menu items in English dialogs.
- Fixed some initial config settings.
- Fixed crash when using playlist menu options with no loaded NSF.

NSFPlay - 12/09/2006
- Written by Brezza > http://www.pokipoki.org/dsa/index.php?NSFplay

by on (#91900)
Wow, looks like something I can use to replace my ageing copy of NotSoFatso! :-)

One thing I've noticed, however, when using the Winamp plugin version: the vumetres / oscilloscope aren't in sync with the actual audio playback. It looks like the visuals start maybe 0.5 seconds too soon. This is the only plugin I see this behaviour with (NotSoFatso for example doesn't behave this way).

Anything I can do to help/debug this?

by on (#91903)
Hmm, that's odd. Yeah, I do see a small lead time (maybe 1/6 of a second); it's really just feeding samples to the visualizer as it writes them to the output, maybe it's necessary to stick in a delay. I dunno. I'll put it on my list of things to look at for the next version, but it is not something that seems terribly important (I will fix it if it doesn't take too much time).

by on (#91926)
I have a different theory based on the behaviour:

It looks like, for example, when clicking Play on a song, the visuals (metres + osc) start immediately, then the audio kicks in 1/6th or 0.5 seconds late.

So it may be that the delay is in when the actual audio playback begins, rather than the visuals "trailing behind". I'm trying to say that I think the audio waveform generation appears to be done immediately (and fed into Winamp immediately, since the visuals start immediately), but the actual audio playback seems to be buffered.

I went looking at the source to see if I could find anything in there that stuck out like a sore thumb, but it's C++, extremely Windows-oriented and Winamp-API-oriented, thus difficult for me to discern what's what. I was trying to see if there's some kind of plugin or playback engine buffering that's going on which would explain it.

I wonder if this is one of the buffering options I have set in Winamp, although I think those are all for streaming (e.g. Shoutcast streams), which wouldn't be relevant here.

by on (#91930)
The visualizer is handed data from SAAddPCMData and VSAAddPCMData in in_module.cpp. Both of these come with a timestamp, however, so I think Winamp is supposed to store them and display the correct one when it's being played.

I can add an arbitrary delay to the timestamp as a hack solution, but I don't think that's really the correct way to fix it, because looking at other plugin sources I don't see anybody else doing that.

Edit: ah, I've found the problem. Winamp's visualizer expects to recieve 576 samples at a time, but the plugin was producing 2048. This was fine for playback, but seems to introduce timing inaccuracy for the visualizer. So... this will be fixed in the next version.

by on (#91936)
Wahoo! I like how they picked some arbitrary value. 576, man. Cuz you know, 576 is better than 459, and it's not as hefty as 2048. Makes lots of sense you know. (Nullsoft... sigh...)

Thanks for looking into this, rainwarrior. <3

by on (#91955)
koitsu wrote:
Wahoo! I like how they picked some arbitrary value. 576, man.

MP3 operates in 576-sample granules. I imagine that this size dictated a lot of the internal data structures of early Winamp.

by on (#91958)
By the way, there was a mistake in ppMCK prior to 2007 with the N163, and NSFs from before then have a problem playing back in NSFPlay (and also NezPlug++, and real hardware AFAIK). The problem stems from poor knowledge of the sample length register, which uses 6 bits for length and not just 3.

Here's a quick fix, if you run into these:

1. You'll need a hex editor. Search the NSF for a string of the following form:

Code:
09 80 9D ?? 06 8D 00 48


There should only be one string that fits this form, and it's probably at an offset in the range $0D00-$1300 somewhere. If there's more than one, something else may be going on.

2. Replace the 80 in that string with E0:

Code:
09 E0 9D ?? 06 8D 00 48


3. Save it, and you should be good.

If you can't find this string in the bad NSF file, then let me know.


For the curious, that string means:

Code:
09 80    = ORA $80
9D ?? 06 = STA $06??, X  ;  (RAM variable)
8D 00 48 = STA $4800     ;  (N163 register)


Changing $80 to $E0 sets all three of the top bits, which unless they are all set will contribute to the length of the sample (making it too long). Old ppMCK versions assumed a maximum sample length of 32, and thought that the high bit was simply an enable bit (it is not, it subtracts 128 from the maximum sample length of 256, the other two bits we are setting subtract 64 and 32).

by on (#96015)
rainwarrior, has there been any development on this? Sorry to sound like I'm expecting some degree of support, I'm not :-) Just curious if there is a debug or test build available with the 576-sample fix.

...I guess I could snag the source and take a stab at it myself. From briefly skimming the source, I assume this requires Visual Studio (I see vcproj files...)? What version of Visual Studio is this known to compile correctly with? I might have to make an XP VM just to deal with this, since I never install Microsoft devtools (they're always a complete clusterfuck) on my native system...

EDIT: Is the 2048 sample count defined in WA2InputModule::PlayThread()? Relevant code below...

EDIT #2: And shouldn't blank_time's divisor (48000) be based on the selected playback sample rate in the GUI (which is usually 44100)?

Code:
DWORD WINAPI __stdcall WA2InputModule::PlayThread(WA2InputModule *_t)
{
  xgm::INT16 *packet_buf;
  int packet_size = 2048 * _t->nch * _t->bps / 8; // バッファサイズ2048bytes固定
  int blank_time = 10 * _t->rate / 48000; // 最初の数パケットは無音にする(DirectX plugin対策)
  int wsize; // dsp処理後の書き込みサイズ
  int sample_size = _t->nch * _t->bps / 8;

by on (#96028)
Yes I have been working on NSFPlay, though it is not my only ongoing project. I am not really expecting to release a new version for a few months.

I do have the fix for the winamp visualizer. The fix is a few lines different in in_module.cpp; if you want the code or a quick build now, e-mail me or PM me. I've been considering lately moving the code into a public repository like Google Code, haven't gotten around to that yet. (edit: okay I've moved it to Google Code, see below)

I wasn't planning to release a new version until I had more significant changes to post. I've mostly been doing hardware tests to verify the emulation accuracy:
- famicom expansions
- PAL DPCM
- linear counter
- MMC5

The accuracy is actually pretty good in most cases. N163 needs a complete rewrite, more or less, to accomodate for new information about it, and the VRC7, even though it's "pretty good", is going to take a lot of work to fix the lingering differences from the real thing.


Edit: I have moved my development workspace for this project to Google Code, in case anybody wants to watch me code things very slowly. http://code.google.com/p/nsfplay/
Re: NSFPlay 2.1
by on (#98377)
Beta testing for version 2.2 begins:

--- file removed, beta over ---

Let me know if you find any problems with this. When I stop getting bug reports I'll do a proper release. The main change is NSFe support, but here's a complete list:

Audio Emulation:
- Unmute on reset now sets $4015 to $0F instead of $1F.
- PAL noise frequency $1 now 8 instead of incorrectly 7.
- New VRC7 patch set, option to select alternative patch sets via VRC7_PATCH.
- 5B polarity inverted, envelope adjusted, volume tweak.
- MMC5 polarity inverted, length counter runs at double speed, highest 8 frequencies are not muted.
- VRC6 $9003 register implemented (controls halt and frequency multiplier)
- VRC6 polarity inverted, phase reset now functions properly.
- FDS now uses NSF header $76/$77 to set up $6000-7FFF memory range.
Other:
- Fixed improper $4015 read implementation (should return length counter status), also DPCM IRQ was not initialized.
- Default focus in keyboard window now the track list (to prevent accidental mouse scroll time expansion).
- Fixed Winamp visualizer timing inaccuracy, changed default keyboard delay/freq.
- Inverted VRC7 volume display in keyboard view.
- NSFe support.
- Added NSFe extension block 'text', contains null terminated string of any length (NSF text).
- Removed broken ENABLE_DCF config option. HPF=256 now correctly disables HPF.
- Rewrote LPF and HPF, should have a more usable range of options now.
- Removed XXX_FR/XXX_FC options, now XXX_FILTER works like LPF for each device.
- Memory R/W access is now exclusive to the first device that accepts it; prevents FDS multi-expansion write conflicts.

Beta versions:

2.2 beta 0 - 8/20/2012
- first beta release

2.2 beta 1
- fixed loop detector bug (false positives causing some NSFs to fade out at 30s)

2.2 beta 2 - 8/26/2012
- fix incorrect pitch on PAL with QUALITY=0
- fix conflicts between keyboard commands and menus
- fix enable periodic noise
- strip whitespace from title string ends
- FDS $4087 bit 7 now silences modulator
- documetation

2.2 beta 3 - 8/28/2012
- fix NSFe bug where track list is not in NSF order (had incorrect playtimes)
Re: NSFPlay 2.1
by on (#98397)
I'm still looking for more bugs, but as for GUI issues:

- NSFe track titles do not appear on the front of the GUI.
- Channel and keyboard note coloration should be the same in keyboard view. Ex: If the SQR0 note on the keyboard is red, SQR0 should be red.
Re: NSFPlay 2.1
by on (#98399)
Hmm, the track title should appear as you have specified in the TITLE_FORMAT option. I forgot to document it but %L/%l is the NSFe song title. The default string should be "%L (%n/%e) %T - %A" unless you've replaced it or are using an old in_yansf.ini file.

As for the colour indicators, I'll think about some way of doing that in a future version.
Re: NSFPlay 2.1
by on (#98409)
I overwrote my old INI file. The NSFe track titles show within the media player, in my case XMPlay, but they do not show up in the NSFPlay GUI.
Re: NSFPlay 2.1
by on (#98413)
Hmm, it's working on my end. Could you attach an example NSFe that doesn't show its track names?
Re: NSFPlay 2.1
by on (#98424)
I believe I'm partially wrong. The track names appear in "Track Info" on the GUI, but not "Plugin Info" in the "NSF Header" section.
Re: NSFPlay 2.1
by on (#98425)
Oh, yeah I didn't put track names in that window.

Actually I'm planning to dump all of the relevant NSFe data into that little misc. frame, but with a button next to it that lets you expand it as a text window and look at all of it easily. Didn't get around to that for this version.
Re: NSFPlay 2.1
by on (#98426)
Minor bug:

nsfplay.txt doesn't document the %L expando for TITLE_FORMAT expansion. I still have no idea what it does, especially when it's used in the default TITLE_FORMAT:

Code:
TITLE_FORMAT=%L (%n/%e) %T - %A


In Winamp 2.5x it seems to generate a whitespace, so the actual default "song string" shown in the player is literally " (xx/xx) Title - Artist" (note the preceding whitespace; sorry, I had to add double-quotes to keep the forum software from stripping the whitespace out).
Re: NSFPlay 2.1
by on (#98428)
Yep, I forgot to document it. That's fixed in svn already, just didn't push a new beta for the doc fix. %L/%l is the NSFe track name (the tlbl chunk, i.e. "track label" which is why it's %L).

Is the leading whitespace when there's no NSFe tlbl chunk a problem? I was trying to pick a default string that would work with NSFe by default but wouldn't look too odd if you were just playing an NSF. The space I thought was a reasonable compromise, since the alternative is to have two TITLE_FORMAT options that are selected between by the presence of a tlbl chunk, which I thought would be needlessly complicated. (Also, to clarify, the whitespace isn't generated by the %L. There's just a space after the %L in the title format string.)
Re: NSFPlay 2.1
by on (#98429)
%L isn't a problem, but I think it should act as a no-op (e.g. NULL) if there's no associated NSFe title, rather than print a whitespace. Is that possible?
Re: NSFPlay 2.1
by on (#98430)
I was just answering it by editing above. That's what it does. The space is the space that follows it in the string.
Re: NSFPlay 2.1
by on (#98504)
Ahh yes, I see. So what about this: if %L is used and the file being played is NSFe, use the NSFe title. If %L is used and the file being played is NSF, it behaves the same as %T. I guess this could effectively nullify the need for %L entirely, so maybe it would make more sense to nuke that and replace %T's behaviour? Sadly I don't know what the repercussions would be / if it would break existing setups.

Basically what I'm trying to get across is that having both %T and %L in the same playback line seems redundant.

Or with NSFe files, does %T actually represent something completely different than %L (and vice-versa)?
Re: NSFPlay 2.1
by on (#98510)
%T is the title of the NSF which is a field present in both NSF and NSFe.

%L is the title of the current track, which is optionally present in NSFe.

e.g. %T="Lagrange Point", %L="Theme of Iris"

If %T is duplicated in %L when %L is missing, you would end up with a title string that looks like "Lagrange Point (1/20) Lagrange Point"
Re: NSFPlay 2.1
by on (#98521)
Ahh got it, got it. Hmm. I wonder how Foobar2000 and some other programs solve this dilemma then (with the "extra space").

I guess one way is after expanding the % expandos you could collapse whitespace (e.g. in perl tr/ //s or the probably-easier-to-understand s/\s+/ /g (\s represents a whitespace in perl regex)) then hand that out as whatever the entire "song string" is. But since this is all in C/C++... well, let's just say I never liked dealing with string parsing/copying/manipulation much in C.

I will state up front I am totally being OCD about it, it's not a deal-breaker in the least, so you can just be like "DEAL WITH IT, GET RID OF %L IN YOUR STRING IF YOU DON'T HAVE NSFe FILES" and that's that, hahaha. :-)
Re: NSFPlay 2.1
by on (#98522)
Well, my thinking was that I wanted someone to get what they request from the TITLE_FORMAT string. I don't really like manipulating it "behind their back" since that tends to get counter-intuitive.

However, I might put something in to trim any leading or trailing whitespace, since there's not really a use for whitespace at the beginning or end. That sounds like a good solution to me.
Re: NSFPlay 2.1
by on (#98523)
Okay cool, I'm fine with that too. Like I said: KISS principle in effect, since I don't have any NSFe files, in my case I can just remove %L and stop complaining, hehehe. :-)

Trimming whitespace off the start/end of the entire "song title" string would be wise. However, I would have to advise against trimming whitespace off the start/end of individual NSF/NSFe fields. I know that personally I've caught a few NSFs which had extraneous whitespace in their song titles (the author seemed to think "32 bytes for title" meant "I need to pad the content with spaces" -- sigh, READ THE SPEC!), and I wouldn't have caught those had I not seen them in Winamp.

Oh, and for the hell of it: My own little NSF archive, where I've been trying to clean up all of the existing NSFs whose composers/authors are wrong, fix composer names in Japanese (going with the naming convention of Firstname LASTNAME (family names/surnames in Japanese are usually written in Romaji in all-caps to denote they're a family name)), fixing incorrect sound chip enable/disable bits in the header, and removing sound effects (those should really be in their own files). I've been meticulous about maintaining that readme.txt every time I make a change. All those composers/etc. I really did have to spend quite a bit of time digging up online -- vgmpf, vgmdb, and wikia.com were super helpful but some others I had to dig for (plus get some folks to translate some Japanese pages). Sadly due to the 32-byte limitation in the original NSF header for composer length I can't fit lots of composers in there. This is where NSFe would, obviously, shine.
Re: NSFPlay 2.1
by on (#98524)
koitsu wrote:
Sadly due to the 32-byte limitation in the original NSF header for composer length I can't fit lots of composers in there. This is where NSFe would, obviously, shine.


You can go around the field size limitation and strip SFX without modifying files by utilizing NEZPlug M3Us. I've been using them for Portable Music History sets and so far haven't run into any problems. They are supported by at least NEZPlug++, NSFPlug/Play and foo_get, so should work for most people. There should be at least a few dozen examples in my collection (http://nsf.joshw.info)

Also, please try not to use Zophar's archive. It's massively outdated compared to my pack. You might fix some files that have already been fixed ages ago. :)
Re: NSFPlay 2.1
by on (#98536)
Alternatively, NSFe's title/artist/copyright fields are of unlimited length.
Re: NSFPlay 2.1
by on (#98552)
Knurek wrote:
koitsu wrote:
Sadly due to the 32-byte limitation in the original NSF header for composer length I can't fit lots of composers in there. This is where NSFe would, obviously, shine.

You can go around the field size limitation and strip SFX without modifying files by utilizing NEZPlug M3Us.

Politely: I think you missed the part of my paragraph where I said composer. :-) I couldn't care less about "track titles". See the official doc for yourself -- all it allows for is 1) track titles, and 2) a way to avoid certain playback of certain song numbers (i.e. a way to skip effects). I would much rather fix the source NSFs or just move to NSFe entirely -- plus it saves disk space (consider filesystems formatted using 32KByte clusters; one M3U file could be 1KByte, but takes up 32KBytes of actual disk) + doesn't waste an inode. On embedded systems/platforms this matters more than you can imagine.

There are also things like your 1943 M3U which has track 16 as "Unused" -- for all we know it's not actually "an unused song" as much at could be "just some gobbledegook that got included in the rip" or even "an incomplete song by one of the composers / isn't used". I throw crap like that out. I can't tell you how many NSFs I've had where there are tracks included (at the end of the song list) that are just previous tracks with certain channels muted and so on. Doesn't serve a purpose, and should just be part of the effects package IMO. Matter of opinion though.

Knurek wrote:
Also, please try not to use Zophar's archive. It's massively outdated compared to my pack. You might fix some files that have already been fixed ages ago. :)

I should probably use your NSFs as source material! :-) The only reason I used the ones on ZD is because 1) I knew about them (didn't know about your site until now), and 2) most of them seemed to be originally ripped by Kevtris (part of his nsfcoll.zip collection from long ago).

However -- and again, politely: though some of your NSFs have had the same fixes I've done (specifically ones with incorrect expansion chip bits set in the header), every song I've looked at so far lacks composer fixups. Did you actually read my readme.txt in full? Your listing has absolutely no mention of what's been changed/fixed/etc.. Like I said in my earlier post, I've been extremely diligent about tracking every single change I make to the NSFs so that people would know what I changed and what I started with. It's not about being OCD -- it's about providing something that says to people "in case you wanted to know what exactly is different in these NSFs...". It's equivalent to a code changelog, and I cannot stress how important that is.

Anyway, this is getting off the topic of the thread. When I posted my NSF ""archive"" link I was like "I probably shouldn't do this, it's going to cause people to start analysing it and blah blah and it has nothing to do with NSFPlay". I really need to trust my gut instinct more.
Re: NSFPlay 2.1
by on (#98562)
koitsu wrote:
Politely: I think you missed the part of my paragraph where I said composer. :-)

Actually, there are tag fields in the header of the M3U that don't have size limitations. Not sure if this is an unofficial user extension, or something NEZPlug+ has added, but I've seen it used by people both here and in Japan. Here's an example:
Code:
# @TITLE       Soldam
# @ARTIST      Jaleco
# @COMPOSER    Atsuyoshi Isemura, Yasuyuki Suzuki, Yasuhiko Takashiba, Takahiro Ogata
# @DATE        1993-08-06
# @RIPPER      ugetab
# @TAGGER      Knurek

# Atsuyoshi Isemura, Yasuyuki Suzuki, Yasuhiko Takashiba composed the original arcade game's music,
# Takahiro Ogata did the Game Boy port arrangements

This works out of the box with foo_gep, and you can use this python script to have them display in Nezplug as well (haven't used NSFPlay for ages, not sure if that works with it). Yes, I'm aware that splitting M3U to micro-files will have a terrible effect on systems with large clusters, I guess I could modify that script to allow for just tagging the M3U without splitting it.

koitsu wrote:
There are also things like your 1943 M3U which has track 16 as "Unused" -- for all we know it's not actually "an unused song" as much at could be "just some gobbledegook that got included in the rip" or even "an incomplete song by one of the composers / isn't used".

I think most of those M3Us are converted from NSFe files, so any issues you (or I, believe me) can have should be taken with NSFe submitter. Many of them are just plain terrible, with bad timers, unverified composer data, using bad NSF rip as a base and other errors like that.

koitsu wrote:
However -- and again, politely: though some of your NSFs have had the same fixes I've done (specifically ones with incorrect expansion chip bits set in the header), every song I've looked at so far lacks composer fixups.

I don't think I did many header fixes, truth be told, I left them for some other, better time. Many thanks for those, BTW.
Most of all the rips there should be the latest correct version (there has been a slew of rerips/fixes that Zophar doesn't host) and should have proper filenames with my naming scheme - Game name (US region priority) [Alt game name if different] (System if not default)(YYYY)(Developer)(Publisher).
I'm currently switching to YYYY-MM-DD release date format, up to G letter at the moment.
Re: NSFPlay 2.1
by on (#98586)
I think this is something introduced in the latest beta:

Esper Dream (FDS).nsf no longer plays anything for any of its tracks. This applies to both the "Zophar Domain version", as well as the version on Knurek's site.

I'm pretty sure this NSF used to work fine, since it's one of the ones in my own archive that I updated to have proper/correct composer names. Yet since I upgraded NSFPlay to the latest beta, nada output.
Re: NSFPlay 2.1
by on (#98589)
Just a reminder that the weird detuning with PAL NSFs when APU1_QUALITY=0 is still there, and seems reproducible both with wine and WinXP.
Re: NSFPlay 2.1
by on (#98597)
Ah, yeah, I hadn't looked into that yet. I do have an XP VM now, maybe I can reproduce it...
Re: NSFPlay 2.1
by on (#98640)
Okay, beta 2, this should fix the PAL QUALITY 0 pitch issue and some other things.

--- removed ---
Re: NSFPlay 2.1
by on (#98750)
Beta 3, fixed a bug with NSFe track times (they were wrong if playlist wasn't in NSF order)

-- file removed, beta over --