kungfufurby / addmusickff Goto Github PK
View Code? Open in Web Editor NEWFork of AddMusicK, a compiler/inserter of music for Super Mario World
Fork of AddMusicK, a compiler/inserter of music for Super Mario World
Currently, the range supported is from zero (o1c
with no transposition) to an 83 (o6b
, normally illegal, but achievable with transposition). Although hardware limitations on pitch limits will cause problems in the positive direction, the negative direction is doable, albeit with a hardware limitation-induced loss of precision.
The code's been sitting there unused, and I think it's time to bring it back. In addition, it wasn't used in vanilla SMW, either.
C++-side is involved because the VCMD ID has to be made valid in order for this to happen.
When the song is switched, the SFX stops playing until the next instrument command is hit or the SFX runs into the end of its own data. The channels are not actually allocated, and the pitch is revealed to have been zeroed out.
The cause of this bug is the pitch base being zeroed out during song initialization.
The ADSR/GAIN command (referring to both $ED $80 xx and $FA $01 xx, when switching from ADSR to GAIN, causes the default instrument's gain to play for a short moment (by my own estimate, less than a tempo tick, probably a sample or two at the absolute minimum) due to the order the DSP registers are written to. This can have an undesired side effect, particularly if the instrument's GAIN byte is set to an absolute volume value.
I was redirected here after hearing you were working on this, except didn't want to touch tie support? I would have added it long ago if I had any idea how to get AMK compiling, but I can do you a pull request to add this in, already got the code.
Oh, and side-note, plus a reason why AMK really does need replacing (working on it): you seem to have the AMK 1.0.8 before it was moderated, meaning you haven't imported the actual released 1.0.8 (it was further changed before it passed moderation).
For those of us that want to just create music and don't want to actually use the music in any hacks, the code that handles the SFX should be stripped away, possibly through an asar define. Additional measures could be taken on the C++-side to not process the SFX lists as needed.
One of the channels is uninterruptible due to there being no SFX that has the ability to interrupt it in the first place. Thus, a custom interruption command should be created for this very purpose.
This has been recorded for quite some time as a .txt file, but hasn't been officially included yet.
To ensure that #69 doesn't result in too much catastrophe down the road, a new HTML file needs to be created that contains an ARAM map. The ARAM memory map will be adapted from all known Addmusic sources and the vanilla Super Mario World sound driver.
Only stable memory locations will be accounted for. In almost all cases, this means only $0000-$0500 ($0000-$0400 for AMK) will be covered. Exceptions will be made for the build used in vanilla Super Mario World within the context of past Addmusic versions directly modifying memory locations within the code.
The documentation will be forfeited if memory location allocation for the variables in question ever become dynamic (which is a possibility, and would result in the $F7 VCMD requiring a makeover, as that makes memory locations even more unpredictable).
The way the VCMD is currently implemented is to simply go back three bytes. Vanilla SMW jumped back one byte. AMK's commentary says play last note.
If $FF as a SFX VCMD is supposed to go back to the last note, then it would simply go back a variable number of bytes until a note was hit.
I just took a look in my jump SFX replica compared to the original. I am missing a one tick delay between pitch slides that the hard-coded version does have, after analyzing both of the raw note values in slow-motion.
This is the sequel to #22.
The original Super Mario World had somewhat of a priority system where certain SFX could not be interrupted by other SFX. I want to re-implement this as a SFX-only VCMD, where smaller values mean less priority (and zero being the default), and ties in priority result in the other SFX being overwritten.
Addmusic405 has a specific VCMD that enables light staccato dating back to Carol's more.bin. Specifically, $E4 $AA
causes the global transposition VCMD to instead enable light staccato. This should be converted to my new light staccato enable VCMD ($F4 $14
). Note that due to the way this is handled in the original code (via a call opcode overwriting the normal fetch operation), it also causes the global transposition value to become $01
because of what the accumulator contained last, which means $F4 $14 $E4 $01
is the actual conversion.
Add in the ability to execute custom code. C++-side will involve having to conjure up something similar to what the SFX code already does.
The current concept of this VCMD is as following...
$FF xx xx yy yy
xx xx
is a little endian pointer to a snippet of SPC700 ASM code.yy yy
is a big endian pointer to a snippet of SPC700 ASM code for the readahead code to execute. (It can also be made little endian, but it saves me a few opcodes to internally designate it as big endian.)
$01
, readahead is terminated with the note keyed off.
$02
, readahead is terminated with the note not keyed off. The second byte also does nothing (and should be set to zero in case I do something in the future that gives the byte a purpose).It just so happens that a previous version of this VCMD once existed in Addmusic405. It was originally VCMD ID $ED $83 xx xx yy yy [zz...]
, with xx xx
being a big endian pointer to where the code will be copied to then executed from, yy yy
being a big endian number indicating the filesize, and zz
being ASM of a filesize of yy yy
bytes.
This, however, has more going for it due to allowing for a variable amount of extra data afterwards (and avoiding complications from readahead). If I ever convert this over, then I would automatically generate a zero for yy yy
... though I would have to do something about the ASM, which would probably be represented in raw hex, and therefore the ARAM locations might not be correctly adapted for AddmusicK's.
Initially reported by Anas on the SNESLab Discord server to my knowledge, but brickblock369 and musicalman have also noted some problems along these lines. May also be related to #16, though that is a failure to set the noise frequency.
When SFX is played while noise is active, the noise will continue to play, but with the frequency set by the SFX. This change will persist until the frequency is changed again by music. If music is changing the noise frequency while SFX is playing with noise, then the SFX will use the new noise frequency instead of continuing to use its own.
We need to figure out a way on how to amicably resolve noise conflicts between SFX and music when it comes to the frequency. Some extra channel muting may be in store here...
This is an offshoot of #16. Echo-related VCMDs are causing the noise to be interrupted until changed externally. Although I understand this from an EDL setup standpoint when clearing the buffer, it is otherwise not a good thing. Multiple echo VCMDs are causing the same kind of interruptions at that.
Reference: HertzDevil/AddmusicK@014a701
HertzDevil's AddMusicK fork (from which I adapted the makefile from) has an updated ADSR Envelope viewer that better represents the ADSR. Port this over to AddMusicKFF (with credit).
Every time the music is changed, the SFX echo channels are supposed to be zeroed out. Currently the Y register is used for this storage, however my slowdown fix pre-dating AddMusicKFF can accidentally cause the Y register to be non-zero if a tick is scheduled to be played immediately when the command to change the music is sent.
This doesn't affect soundtracks being inserted into the Super Mario World ROM. Instead, I caught a stack underflow caused by a timer 0 value not being pushed into the stack, decrementing the stack pointer by one (due to the starting memory location being placed after the timer read) in compiled SPC files, causing memory location $01D0 to have values written to it via the stack. This would interfere with SFX in channel 1 (or #0 according to MML) due to corrupting a pointer.
Pitch envelopes actually freeze when SFX is playing while an arpeggio is running. This applies to both the standard SFX data format (done by CPUIO0 and CPUIO3) and the hardcoded SFX (done by CPUIO1, which mainly affects the jump SFX).
The noise frequency is being zeroed out when a song restarts after looping due to an auto-generated echo buffer reserve VCMD (even when it's zero). This isn't related to #72, as the cause of the frequency going wrong is different. It may be related to #16, but only if something echo-related is interfering with the noise frequency, since a zero noise frequency is the cause in both cases.
Turns out the fine tune VCMD is interfering with the note pitches of the SFX by adjusting them slightly... meaning it becomes quite noticeable at higher offsets.
Although there is an option for the P-Switch to be featured as SFX on the SPC700-side, there is no corresponding 65816 code on the SNES side to implement the P-Switch as SFX, probably because of its incomplete implementation.
Requires #44 to be implemented first before this one can be properly done.
Requested by imamelia on the SMWCentral forums.
This is currently in the conceptual phase, because of memory location shenanigans that I would have to do to make this work. This will take teamwork from the C++-side, the SNES-side and the SPC700-side to get right.
Currently I'm thinking of using a one ID system for globals and locals, and an optional two-ID system with quoted pathnames on custom song groups by name: one required ID for the master ID, and a second ID for a fixed sub-tune ID (this must not be less than the highest global song ID, and if not defined, occupies the last known slot, which usually increments sequentially). The master ID is allowed to be duplicated across song groups under the condition that it is the exact same track.
In addition, I will allow the use of the #
character to refer to non-global, non-local groups to include in a song.
Locals are by default single songs, and also count as a unique song group of one song. They automatically take up the lowest non-global sub-tune ID. These should be defined after all other groups to prevent complications with tracking IDs manually.
To implement the dynamic pointer scenario, p4plus2 proposed a simple relocation table method. For me, it simply means swapping in and out pre-computed pointers that are already computed wherever needed, and it is only needed if there is a song that belongs in more than one song (being in the local section counts as being in a unique song group). I have ultimately decided that I shouldn't do this citing a factorial factor down the road, so instead I came up with something that won't require scanning the raw data format. See #133 for further details.
This concept can also be expanded to dynamically load VCMD code on the fly, but that's a little bit out of scope.
When song groups are loaded, all of the samples must be accounted for that are defined on a per-song basis, and the sample IDs used can get quite a good deal inconsistent. This will be a very interesting conflict to resolve if one uses #default
and the other uses #optimized
as a nice example case...
Outside the scope of sample group conflicts, for the extra samples, I think I can upload them by real sample ID (taking care to account for duplicates), and then make a table to convert them to the expected sample ID that the song data expects. This would also only apply to the custom song groups: locals don't have this problem since they're just a single song.
We also need to take care of #instruments
. Custom instruments can end up duplicated in each song, and therefore I feel that we can partially obsolete the AMK-style header and instead put them all just before the songs, giving them a nice, fixed location to be housed at. Instead, taking its place will be a translation table. Global songs with custom instruments will have their own array separate from the song groups. See #131 for further details.
Globals:
01 Silence.txt
02 Fanfare.txt
InGameFanfares:
03 "Stage Clear.txt"
04 "Invincibility.txt"
05 "Death.txt"
InGameMusicSet1:
#InGameFanfares
06 08 "Stage Theme 1.txt"
InGameMusicSet2:
#InGameFanfares
07 08 "Stage Theme 2.txt"
InGameMusicSet3:
#InGameFanfares
08 08 "Stage Theme 3.txt"
09 06 "Secret Area Theme 1.txt"
0A 07 "Secret Area Theme 2.txt"
MenuThemes:
0B 06 "Main Menu.txt"
0C 07 "Options.txt"
0D 08 "Password.txt"
0E 09 "Nothing To See Here.txt"
03 0A "Stage Clear.txt"
Locals:
0F Title Screen.txt
10 Ending.txt
11 Game Over.txt
Currently only global transposition is accounted for here, and not per-channel transposition.
SFX is only supposed to play its own pitch envelopes defined by its own $DD and $EB VCMDs. For whatever reason, it ends up using the pitch envelope VCMDs (not counting $DD, since that doesn't carry naturally) as defined by the music if they're used in the song.
The code's been sitting there unused, and I think it's time to bring it back.
C++-side is involved because the VCMD ID has to be made valid in order for this to happen.
A code analysis of the original caused me to realize that these could be converted into data that could be used by the SFX engine without having to hardcode everything, since the memory locations being utilized are actually recycled. The jump SFX has already been attempted, but I will plan on replacing the one in there with a more accurate version.
AddMusic405's $ED $80
VCMD did DSP register writes that automated the voice-specific part when the third byte, $?x
, is $09
or less (one of the slots included are technically read-only, and thus won't qualify for this task, and the original source used a BCC against $0A
, thus excluding that value). This should be converted into the $FA $08-$0F
VCMDs that do the same thing, except with one parameter byte subtracted due to de facto embedding it into the VCMD ID.
I'm interested in adding phrase support to make use of a feature that has been barely used, and may be useful in a few cases for reducing the memory footprint.
I'm open to discussion, but this is what I have so far planned as an example...
#phrase
#0#1#2#3#4#5#6#7
/
[[
(0)[#8#9#10#11#12#13#14#15]
#16#17#18#19####
]]2
#20#21#22#23#24#25#26#27
(0)
#endphrase
The phrase directive starts a phrase list, and can only be defined once. It must be placed before any track data, and is terminated by endphrase.
Each phrase entry is one line consisting of a set of up to eight tracks, one per channel, defined by ID. There is also support for labels (complete with sections to define, whether it be one or multiple entries in one go), but they do not act like the $E9 VCMD: instead, they act as sections to copy outright. Superloops are also supported, and will reproduce the jumpback command. No nesting is supported, though.
The intro marker (/
) and misc. (?
) markers are also supported to indicate looping and non-looping songs, though for the misc. marker, I recommend putting it at the beginning before all of the track definitions.
Note that normally 128 and up are infinite loops. I may make this so that only 255 triggers the infinite loop.
Also, some internal structure modification will be required. Currently #0
-#7
are alright, but #8
is reserved for all of the labels, and I think there's another one for remote code. Instead, I may have to make this so that a completely separate variable houses the labels and remote code.
I accidentally discovered while fooling around with the sound effect data that pitch slides in SFX are always executed instantaneously without delay, leaving the $DD and $EB commands with one wasted parameter byte each, since the bytes are written, but not read. I want to implement this for the sake of (technically) being faithful to the music variant's $DD and $EB pitch slide commands.
The following VCMD IDs are involved from the original...
$FA $07
(previously just $FA
) - Set Special Wave Oscillation Frequency
$F4 $04
- Reset Special Wave
The SRCN ID must be manually defined, which I will handle automatically via detecting samples and manually inserting a VCMD ID. For AddMusicM, this is a fixed value. For all other cases, this is not a fixed value.
Thanks to me having constructed a memory map beforehand, I can determine which memory locations match between Addmusic405 and AddMusicK and mark them as safe to overwrite.
In addition, because all past builds prior to AddMusicK overwrite vanilla Super Mario World sound driver memory locations, I can add some additional cases and translate them accordingly. Some will require a VCMD from my new VCMD collection (specifically, light staccato).
UserDefines.asm should be created for the user to enter their own defines in. These defines will also allow me to reuse them between the SNES-side and SPC700-side to prevent unimplemented things from breaking the game.
Corell reported a crash bug when global songs use echo and the local song either doesn't use echo at all or uses an EDL that doesn't match the value used in a global song.
This specifically allows for longer strings on the tagging variables. Plus, we get to use new ones down the road!
I want to consolidate the two instances of the jump SFX into one, but I ran into a complication in that they are defined in two different folders, meaning that I currently can't consolidate them into one instance.
Thus, I want to be able to define a duplicate SFX pointer from another folder and have it not be wasted duplicate data.
Arpeggio is failing to continue playing after a CPUIO1 sound effect is triggered. The cause is a memory location being zeroed out reserved for arpeggio.
This documentation is inaccurate, mainly because of an incorrect command name, but also because it either doesn't use the samples from the lowest-numbered global song or something else is going on...
Irregardless of case, the way it currently works is that I'm not sure if it's scanning the samples of the lowest-numbered global song, but it does use the samples of the song you select to convert with that! Then again, that was in conjunction with the -norom
flag and a single .txt file to convert...
I may end up making -sfxdump
an actual alias of -dumpsfx
for the sake of allowing the inaccuracy to technically be correct past a certain version.
I discovered a song compiler freeze on the $DD command (slide to note). The song compiler is programmed to accept a MML note as a target note, but if an octave is specified prior to the note, it results in the song compiler freezing altogether, producing no further output.
The SPCs that are created by AddMusicK fail to play noise-based SFX due to a failure to set up the FLG register. I intend to investigate why...
arch spc700-raw
is being deprecated and removed in future asar versions. Thus, some modifications need to be made for forward compatibility in the future.
Special thanks goes to p4plus2 for notifying me of this!
This kind of works like the *
command in MML... but with some fine print.
$F4
series and one in the $FA
series): one for a single call only, and one for multiple loops.*
(unless maybe I up the parser version to 4). This is because it doesn't appear to account for recalled label loops properly, and thus would cause incorrect subroutine references.The instrument is not properly restored when a CPUIO1 SFX is done playing because the instrument table itself is uninitialized.
Readahead is freezing the sound driver due to a 256-byte wraparound when encountering long chains of non-note commands, most noticeably a long chain of subroutines.
Due to a quirk in the original code (which I also discovered was technically by design, but for me it doesn't feel natural), the arpeggio command ignores rests to the point that they actually keep playing all the way through, rather than briefly stopping. To me, it feels abnormal: I would rather have it do its thing, then don't play any note when a rest is triggered, rather than do everything and play the note despite the rest normally saying to key it off.
This was reported by Akaginite on the SNESLab Discord server. If the sound driver filesize has a low byte of $53, it could cause AddMusicM detection to go off.
Since the program is trying to detect a RATS/STAR tag (gotcha!), it simply means I need to check more bytes to avoid this problem.
This kind of optimization will cut down on the number of bytes to look at before deciding whether or not to key off a note, which can potentially reduce slowdown in the long run.
Whenever an arpeggio is initialized on a note, it has a tendency to output a click at the beginning. The cause is keying it on immediately after setting it up (within a few samples of the actual KON queue routine keying it on), rather than adding it to the list of channels to key on.
Arpeggio is only actually functioning on the first channel (referring to # 0 in an MML file) due to a failure to use indexed references in a few places.
The vibrato fade VCMD ($EA) does not keep track of 256ths. This results in a loss of precision, and leaving it incapable from fading in from zero when the number of ticks to fade in is longer than the resulting depth.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.