;------------------------------------------------------------------------------ ; PCMNSF (C) 2010 Mukunda Johnson, Andrew Richards ;------------------------------------------------------------------------------ .import __CODE_SIZE__ .import __CODE_LOAD__ .import __ZPCODE_LOAD__ .import __ZPCODE_RUN__ .import __ZPCODE_SIZE__ .import __RAMCODE_LOAD__ .import __RAMCODE_RUN__ .import __RAMCODE_SIZE__ ;================================================================================= .segment "HEADER" ;================================================================================= .byte "NESM", 1Ah ; marker // .byte 01h ; version // .byte 01h ; number of songs // .byte 01h ; starting song // .word __CODE_LOAD__ ; load address // .word __init ; init address // .word __play ; play address // .byte "hurf durf" ; song name // .res 32-9, 0 ; // .res 32, 0 ; artist // .res 32, 0 ; copyright // .word 0411Ah ; NTSC speed (60hz) // .byte 0, 1, 0, 0, 0, 0, 0, 0 ; bankswitch init values // .word 0411Ah ; PAL speed (60hz !) // .byte 0 ; PAL/NTSC bits // .byte 0 ; EXT chip support // .byte 0, 0, 0, 0 ; expansion bytes // ;================================================================================= ;____________________________________ ;// memory bank access: / ;//----------------------------------. ;// [8xxx] Program Code / ;// [9xxx] Volume Mul. Table / ;// [Axxx] Channel 1 Sample Window / ;// [Bxxx] Channel 2 Sample Window / ;// [Cxxx] Channel 3 Sample Window / ;// [Dxxx] Channel 4 Sample Window / ;// [Exxx] Unused / ;// [Fxxx] Sequencer Data Window / ;//----------------------------------' ;------------------------------------------------------------------------------ ; registers used ;------------------------------------------------------------------------------ APU_CTRL = 4015h DAC = 4011h ;------------------------------------------------------------------------------ ; total cycle measurements ;------------------------------------------------------------------------------ .define CYCLES_FOR_MIXING 126 ; adjust for sampling rate/load (sr=1789773/cps) .define CYCLES_FOR_UPDATE 40 ; cps = both measurements added ;------------------------------------------------------------------------------ ; macro for returning from update routines ; ; jumps to proper return address depending on how many cycles were used ;------------------------------------------------------------------------------ .macro uret vector, cycles lda # uret UV_CH1LP_TESTEND, 16 ;-------------------------------------------------------------------------------------------- @restart: ; restart pattern reader lda pattern_reset ; 4| sta pattern_L ; 3| lda pattern_reset+1 ; 4| ora #0f0h ; 2| sta pattern+1 ; 3| ldx pattern_reset+2 ; 4| stx pattern+2 ; 3| stx $5fff ; 4| 27 uret UV_CH1LP_TESTEND, 44 ; (pood) ;--------------------------------------------------------------------------------------------- rs_over1: rs_overfunc 0, rs_return1 rs_over2: rs_overfunc 1, rs_return2 rs_over3: rs_overfunc 2, rs_return3 rs_over4: rs_overfunc 3, rs_return4 ;--------------------------------------------------------------------------------------------- .macro loop_functions prefix, idx, final .scope prefix ;============================================================================== testend: ;============================================================================== ldx ch_sample(idx) ; 3| check for loop lda ch_read_h(idx) ; 3| and #0fh ; 2| cmp sample_end_h, x ; 4| bne @notend1 ;3/2| lda ch_read_b(idx) ; 3| cmp sample_end_b, x ; 4| bne @notend2 ;3/2| uret UV_CH1LP_LOOPSOUND+idx*4, 23 @notend1: nop ; +2 waste cycles nop ; +2 nop ; +2 lda <99h ; +3 @notend2: uret final, 24 ;============================================================================== loopsound: ;============================================================================== sec ;2 | ldx ch_sample(idx) ;3 | lda ch_read_l(idx) ;3 | sbc sample_loop_l,x ;4 | sta ch_read_l(idx) ;3 | lda ch_read_h(idx) ;3 | and #0fh ;2 | sbc sample_loop_h,x ;4 | and #0fh ;2 | ora #0a0h+idx*10h ;2 | sta ch_read_h(idx) ;3 | lda ch_read_b(idx) ;3 | sbc sample_loop_b,x ;4 | sta ch_read_b(idx) ;3 | sta $5ffa+idx ;4 uret final, 44 ; MAXIMUM CYCLE USAGE! 44 (52) .endscope .endmacro ;loop_functions ch4lp, 3, UV_CH1LP_TESTEND loop_functions ch4lp, 3, UV_CHECKUPDATE loop_functions ch3lp, 2, UV_CH4LP_TESTEND loop_functions ch2lp, 1, UV_CH3LP_TESTEND loop_functions ch1lp, 0, UV_CH2LP_TESTEND ;============================================================================== check_update: ;============================================================================== dey ; 2| bne @update_delay ;3/2| 4/5 ;------------------------------------------------------------------------------ @start_update: ;------------------------------------------------------------------------------ lda pattern_L ; 3| cmp #240 ; 2| check if we need to increment block/bank bcc :+ ;3/2| ->8 sbc #240 ; 2| inc pattern+1 ; 5| bne :++ ;3/2| ->17 ;------------------------------------------------------------------------------ ldy #$f0 ; 2| sty pattern+1 ; 3| inc pattern+2 ; 5| ldy pattern+2 ; 5| sty $5fff ; 4| tay ; 2| uret UV_READ_CBITS12, 41 ;------------------------------------------------------------------------------ : ldy 99h ;align cycles to 23 nop ; nop ; nop ; : tay ; ;------------------------------------------------------------------------------ uret UV_READ_CBITS12, 23 @update_delay: uret UV_CH1LP_TESTEND, 5 ;============================================================================== mid_update_checkpoint: ;============================================================================== cpy #240 ; 2| test for sequence page overflow chance bcc @quit5 ;3/2| ;------------------------------------------------------------------------------ tya ; 2| lower offset -= 240 sbc #240 ; 2| tay ; 2| ;------------------------------------------------------------------------------ inc pattern+1 ; 5| increment page, catch overflow bne @quit18 ;3/2| ;------------------------------------------------------------------------------ lda #0f0h ; 2| increment bank index sta pattern+1 ; 3| inc pattern+2 ; 5| lda pattern+2 ; 3| sta $5fff ; 4| uret UV_READ_CBITS34, 34 ;------------------------------------------------------------------------------ @quit5: uret UV_READ_CBITS34, 5 ;------------------------------------------------------------------------------ @quit18: uret UV_READ_CBITS34, 18 ;------------------------------------------------------------------------------ ;------------------------------------------------------------------------------ .macro ute label, name ; update table entry macro name: .word label .endmacro ;------------------------------------------------------------------------------ ;============================================================================================ ; update vector table ;============================================================================================ ; align by 256 to avoid page-crossing cycle penalty .align 256, $ab update_table: ute ch1lp::testend, UV_CH1LP_TESTEND ute ch1lp::loopsound, UV_CH1LP_LOOPSOUND ute ch2lp::testend, UV_CH2LP_TESTEND ute ch2lp::loopsound, UV_CH2LP_LOOPSOUND ute ch3lp::testend, UV_CH3LP_TESTEND ute ch3lp::loopsound, UV_CH3LP_LOOPSOUND ute ch4lp::testend, UV_CH4LP_TESTEND ute ch4lp::loopsound, UV_CH4LP_LOOPSOUND ute check_update, UV_CHECKUPDATE ute update_end, UV_UPDATEEND ute mid_update_checkpoint, UV_MIDUPDATE ute read_cbits_12, UV_READ_CBITS12 ute read_cbits_34, UV_READ_CBITS34 ute ch1::test_read_source_reset, UV_CH1_TESTREADSRC ute ch1::set_source, UV_CH1_SETSOURCE ute ch1::test_apply_offset, UV_CH1_TESTOFFSET ute ch1::apply_offset_part2, UV_CH1_OFFSET2 ute ch1::apply_volume, UV_CH1_VOLUME ute ch1::apply_rate1, UV_CH1_RATE1 ute ch1::apply_rate_copyh, UV_CH1_RATECOPYH ute ch1::slide_rate, UV_CH1_SLIDERATE ute ch1::copy_rate, UV_CH1_COPYRATE ute ch2::test_read_source_reset, UV_CH2_TESTREADSRC ute ch2::set_source, UV_CH2_SETSOURCE ute ch2::test_apply_offset, UV_CH2_TESTOFFSET ute ch2::apply_offset_part2, UV_CH2_OFFSET2 ute ch2::apply_volume, UV_CH2_VOLUME ute ch2::apply_rate1, UV_CH2_RATE1 ute ch2::apply_rate_copyh, UV_CH2_RATECOPYH ute ch2::slide_rate, UV_CH2_SLIDERATE ute ch2::copy_rate, UV_CH2_COPYRATE ute ch3::test_read_source_reset, UV_CH3_TESTREADSRC ute ch3::set_source, UV_CH3_SETSOURCE ute ch3::test_apply_offset, UV_CH3_TESTOFFSET ute ch3::apply_offset_part2, UV_CH3_OFFSET2 ute ch3::apply_volume, UV_CH3_VOLUME ute ch3::apply_rate1, UV_CH3_RATE1 ute ch3::apply_rate_copyh, UV_CH3_RATECOPYH ute ch3::slide_rate, UV_CH3_SLIDERATE ute ch3::copy_rate, UV_CH3_COPYRATE ute ch4::test_read_source_reset, UV_CH4_TESTREADSRC ute ch4::set_source, UV_CH4_SETSOURCE ute ch4::test_apply_offset, UV_CH4_TESTOFFSET ute ch4::apply_offset_part2, UV_CH4_OFFSET2 ute ch4::apply_volume, UV_CH4_VOLUME ute ch4::apply_rate1, UV_CH4_RATE1 ute ch4::apply_rate_copyh, UV_CH4_RATECOPYH ute ch4::slide_rate, UV_CH4_SLIDERATE ute ch4::copy_rate, UV_CH4_COPYRATE ;============================================================================================= .macro copy_memory_with_banks_ab source, dest, size ;============================================================================================= .local @loop1 lda #0 sta data1 lda #((>source) & $f) | $a0 sta data2 ldy #(>source >> 4) - 8 sty $5ffa iny sty $5ffb lda #dest sta data4 ldy #size sta data6 sec @loop1: lda (data1),y sta (data3,x) iny bne :+ inc data2 : inc data3 bne :+ inc data4 : lda data5 sbc #1 sta data5 lda data6 sbc #0 sta data6 ora data5 bne @loop1 .endmacro ;============================================================================================= __play: ;============================================================================================= ; load code ;--------------------------------------------------------------------------------------------- copy_memory_with_banks_ab __ZPCODE_LOAD__, __ZPCODE_RUN__, __ZPCODE_SIZE__ copy_memory_with_banks_ab __RAMCODE_LOAD__, __RAMCODE_RUN__, __RAMCODE_SIZE__ ;--------------------------------------------------------------------------------------------- lda #zerovol ; .repeat 4, i ; sta ch_read_h(i) ; .endrepeat ; lda #volume_table_start .repeat 4, i sta ch_volmap_h(i) .endrepeat ; lda #0 ; .repeat 4, i ; sta ch_rate_l(i) ; sta ch_rate_h(i) ; .endrepeat ; ;--------------------------------------------------------------------------------------------- ;--------------------------------------------------------------------------------------------- lda #0 ; load pattern address sta pattern ; lda pattern_reset ; init pattern address sta pattern_L ; lda pattern_reset+1 ; ora #0f0h ; sta pattern+1 ; ldx pattern_reset+2 ; stx pattern+2 ; stx $5fff ; ;--------------------------------------------------------------------------------------------- ; :::other initialization here:::: ldy #1 jmp mix_next_sample ;============================================================================================= __init: ;============================================================================================= ; hurf durf rts