Language…
3 users online: fanfan21, Seamus Sinclair, Zavok - Guests: 317 - Bots: 115
Users: 70,443 (2,478 active)
Latest user: TomBrooks

Song Title

    100%

    SMW Central Production 2 - Machine-Made Mayhem

    SMW Music → SMW Central Production 2 - Machine-Made Mayhem

    Turn on JavaScript to preview files without downloading them.

    Submission Details

    Name: SMW Central Production 2 - Machine-Made Mayhem
    Authors: KungFuFurby, Magi, Masashi27, Torchkas
    Added:
    Insert Size: 0x30CB bytes
    Type: Song
    Sample Usage: Many
    Source: Original
    Duration: 5:16
    Featured: No
    Description: A long, upbeat, rave party-esque factory song that goes well with a rhythm-based level, a dance party-inspired level,a factory that focuses on heavy machinery or a very long factory level. Plays in Incineration Station and Musical Mechanisms.
    Tags: athletic final industrial night urban
    Comments: 10 (jump to comments)
    Rating:
    5.0 (1 rating)
    No rating
    Download 75.04 KiB | 291 downloads ▶   Play SPC

    Comments (10)

    HammerBrother Link
    Norveg:
     KungFuFurby Author Link
    Originally posted by HammerBrother
    Which is why I made the code instead of detecting ticks, it detects beats, which will not miss a beat.

    There's a comment mentioning that a tick could be missed, especially if the song plays really fast and/or the game is lagging. Using a series of CMP : BCC to split up the song divided by these events (NSMB "bah") and knowing if the current tick is outside the range is one way it will never miss the given tick, even if it advances past it.

    And, wait, the song was originally $C0 ticks per beat? This version is $30 ticks per beat.


    Truth be told... I was going by the way the original SNES-side code was handling things on the level Musical Mechanisms. Musical Mechanisms "wraps around" every $C0 ticks using the internal multiplication/division registers that the SNES has (this is also AddmusicM's behavior, which increments the high byte and which this operation replicates on the SNES side to some degree). It only reads the remainder in this case when handling the level code: it otherwise doesn't need the quotient. That particular comment I had was to avoid a wraparound desynchronization because it was not a power of 2: instead, it is divisible by 3.
    HammerBrother Link
    Psst. This music file contains a rhythm mechanic left over from SMWCP2:
    Code
    "VCMD_SNESSYNC=$F4$05"
    [...]
    VCMD_SNESSYNC
    VCMD_SNESSYNC
    ;Yes, we need two of these for toggling reasons: both of them reset the
    ;clock, but the flag to run the clock is toggled. Thus, we need to do this
    ;twice. Also, at the end of a phrase, only #0 is processed, thus this is the
    ;only safe place to put these VCMDs just before looping.


    Here's the uberasm level code I made myself (the division is made by Akaginite) that detects a beat:
    Code
    ; To get the current beat "index" (zero-based), divide the song ticks by ticks-per-beat.
    ; The music have $0030 ticks between each beat. This means each frame we take a value in
    ; $7FB004 (AMK's default RAM music track position), and divide by $0030. The quotient
    ; (rounded down) represents the current beat of the song. We can then have a freeram
    ; that stores the current beat, and when the song advances to the next beat, the result
    ; of the quotient would not be equal to the value in the freeram, and we can check if it
    ; is not equal, then a beat has been advanced. After this, we update that freeram so
    ; that each next beat will be detected and also not execute each frame during that beat.
    ;
    ;Notes:
    ; -Because of division, it is obvious this only works with music with consistent number
    ;  of ticks per beat. The song also must loop and end the intro exactly on a beat, and
    ;  the track position should reset when this happens.
    ; -Music on a SNES runs on a separate, independent "thread" than ASM code, this means a
    ;  code that runs every frame will not always be a consistent amount of musical ticks
    ;  advanced. Which results in ticks being missed:
    ; --Checking if the song is on a specific tick (including non-rhythem mechanic, such as
    ;   NSMB's "bah") can fail as the song may advanced past that specific tick before a
    ;   code that checks the tick can detect that. This is more likely if the song's tempo
    ;   is fast enough and/or if the beat check per second (60 checks per second if every
    ;   frame barring lag) is low enough (such as the game is lagging).
    ; --Instead of checking if the music track is on a specific beat, have a RAM
    ;   representing a interval threshold (beats or ticks) that if the song's position is
    ;   on OR anywhere after it trigger an event AND modify that RAM to prevent executing
    ;   the event every frame during that beat/specific-tick.
    ; -There are cases where the game briefly pauses (such as $9D and $13D4) where the song
    ;  is still playing (when pausing, the game pauses instantly but the song continues
    ;  playing briefly before stopping).
    
    
    	!Freeram_CurrentBeat = $60		;>[2 bytes] Beat counter, finds out if the song is on a different beat
    	!AMK_MusicPosition = $7FB004		;>AMK's song position in ticks, see AddmusicK_X.X.X/asm/SNES/patch.asm
    	!BeatPeriod = $0030			;>Number of ticks per beat.
    	!Debug = 1				;>Display song tick position (4-digit hex number) on status bar: 0 = no, 1 = yes.
    	!Debug_StatusBarPos = $0F0A|!addr	;>Position of where to display the song position (if !Debug == 1)
    	
    	init:
    		REP #$20
    		LDA #$0000
    		STA !Freeram_CurrentBeat
    		SEP #$20
    	RTL
    
    main:
    	if !Debug != 0
    		LDA !AMK_MusicPosition
    		AND.b #%00001111
    		STA !Debug_StatusBarPos+3
    		LDA !AMK_MusicPosition
    		LSR #4
    		STA !Debug_StatusBarPos+2
    		
    		LDA !AMK_MusicPosition+1
    		AND.b #%00001111
    		STA !Debug_StatusBarPos+1
    		LDA !AMK_MusicPosition+1
    		LSR #4
    		STA !Debug_StatusBarPos+0
    	endif
    	
    	REP #$20
    	LDA !AMK_MusicPosition
    	STA $00
    	LDA.w #!BeatPeriod
    	STA $02
    	SEP #$20
    	JSR MathDiv
    	REP #$20
    	LDA $00				;>Live beat
    	CMP !Freeram_CurrentBeat	;>Current beat
    	BNE .BeatAdvanced		;>BNE so if the song advanced to the next beat or the song loops, would trigger. Also prevents executing multiple times within a beat
    	SEP #$20
    	RTL
    	
    	.BeatAdvanced
    	STA !Freeram_CurrentBeat	;>Update current beat (results next frame not to execute again unless the beat advances)
    	SEP #$20
    	;Code here is where it execute at every beat of the song.
    		REP #$20		;\Example: Teleport Mario 8 pixels up.
    		LDA $96			;|
    		SEC			;|
    		SBC #$0008		;|
    		STA $96			;|
    		SEP #$20		;/
    		RTL
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; 16bit / 16bit Division
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ; Arguments
    ; $00-$01 : Dividend
    ; $02-$03 : Divisor
    ; Return values
    ; $00-$01 : Quotient
    ; $02-$03 : Remainder
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    
    MathDiv:	REP #$20
    		ASL $00
    		LDY #$0F
    		LDA.w #$0000
    -		ROL A
    		CMP $02
    		BCC +
    		SBC $02
    +		ROL $00
    		DEY
    		BPL -
    		STA $02
    		SEP #$20
    		RTS

    Info that I found:
    • Including the intro, the song length in ticks is $8700.
    • The intro ends at $0900.
    • When the song loops back to the end of the intro, the song position will reset to $0000 instead of $0900. This means that the song structure is now offset by -$0900.
     KungFuFurby Author Link
    Yup, it was made for $C0 ticks a beat because of the original song and the SNES ASM's design in the original game. And that is correct on the resetting. Due to technical limitations, I have to reset the sync clock to zero instead of $0900 (and I call the SNES sync command twice in order to reset it outright instead of accidentally stopping it). However, I know of a N-SPC variant that I think does somewhat similar tracking that does have this kind of support of resetting to a non-zero value: specifically, Nintendo/Akito Nakatsuka, where there is a VCMD that saves the timer value to somewhere else. The timer value is refreshed on some kind of phrase-related jump. It is only present on Heisei Shin Onigashima - Kouhen and Heisei Shin Onigashima - Zenpen.

    Also, the pause SFX behavior it was adapted for was A Super Mario Central Production 2's. That game immediately stops the music on pausing, but plays the pause SFX. Stock AddmusicK has a different mechanism (but then again, it was changed to some degree after 1.0.5, which was the original stock AddmusicK version that was forked off of in the long run).

    If you are tracking by raw tick counter and going after specific ticks, I highly recommend using bcc (less then) and bcs (greater than or equal to) instead of bne or beq.
    HammerBrother Link
    Which is why I made the code instead of detecting ticks, it detects beats, which will not miss a beat.

    There's a comment mentioning that a tick could be missed, especially if the song plays really fast and/or the game is lagging. Using a series of CMP : BCC to split up the song divided by these events (NSMB "bah") and knowing if the current tick is outside the range is one way it will never miss the given tick, even if it advances past it.

    And, wait, the song was originally $C0 ticks per beat? This version is $30 ticks per beat.
    Cote de Boeuf Link
    This and Iron Notes of Industry really "make" SMWCP2's endgame for me, great work.
     KungFuFurby Author Link
    That's exactly why I provided that explanation. Roughly the first minute or so was ported over before I redid the sound design, and I did indeed inherit some of the MML and sample work from that version (particularly the one I marked as PlokDKC3GuitarFourthChord.brr: I didn't create that chorded .brr file, it was from the initial port).

    Most of the other stuff from the initial port was either raw BRR files from other SNES games or were converted over from a non-SNES game. With regards to the non-SNES sources, I inherited the kick used during the first 20 seconds or so of the song, but I downsampled and looped it. I don't remember where the wind came from, but I also inherited that from the original port from the BRR that was already made from it.
    Torchkas Author Link
    You did a stellar job KFF. I'm okay with my name being on here, even though I had little to do with the final version, but most of the work here is by KungFuFurby!
    HammerBrother Link
    Not sure why this somewhat reminds me of “Just shapes and beats” musical style. Also this is in 2nd place on the longest original song, just under YUMP 2 - Bowser's Castle

    Also, this song is almost as long as the full version of bad apple, just being a second shorter than it.
     KungFuFurby Author Link
    Hello everybody! I'm here for some commentary on this song.

    First, here's a breakdown...
    - Masashi27 created the original version of the song.
    - Magi revamped the song and made a MP3 render of it.
    - Torchkas started porting it over, but didn't finish it. I ended up asking to collaborate (well... it kind of turned out that way: I provided my beta as things went on, though I don't remember anything else on the other side. I ended up redoing the sound design anyways), which was accepted. The process took longer than expected because of my own dissatisfaction of AddmusicK, causing me to go back to my fork (said fork, though more C++-side than SPC700-side since I decided it wasn't worth it to try to revamp the code since it was already custom in the first place), ended up being used in the final build). Torchkas's contribution in the final version was some MML for the first portion of the song (though I didn't take all of it in the long run) as well as some of the samples (with me doing some additional editing), hence the credit.
    - I handled the final version of the song you hear here. Yes, it has a wavetable effect at the very beginning, courtesy of the filter steps. Although I did some customizations earlier, 3:00-5:16 in particular were mine (yeah, I may have gone overboard there...).

    A few notes about this song for usage...
    - The version you see here uses pure #optimized. Torchkas had asked I use the originals if I used the stock samples, which I partially accepted for the distorted guitar and slap bass (most of the other waveforms I didn't bother with, and on one of them I used my own smaller copy because I wasn't happy with the optimized one and the default one may or may not run into hardware pitch overflow issues, since I used a shrunken one). It's not like that here because AddmusicK 1.0.8 auto-optimizes non-sample group samples that aren't used in the music, and this would result in an ugly situation for SFX, especially since it has inconsistent handling when compiling for ROMs.
    - The insert size is about 0x200 bytes larger than what it is in SMWCP2's ROM. This is because $DD's target note doesn't play nice with $FA $02, and I specifically patched that for SMWCP2 (it's a very small patch). Thank goodness I didn't squeeze too much out of this...
    - Although I have a few safeguards in here when transitioning from other global songs that use echo (though some known bugs with those kind of interactions can make this situation a bit ugly), please do not enable echo for SFX with this song, since I use inconsistent FIR coefficients in the song. This also includes all zeroes to properly clear out the buffer at some points.