asm file with a dcm sample?

Discuss NSF files, FamiTracker, MML tools, or anything else related to NES music.

Moderator: Moderators

Post Reply
Tompis1995
Posts: 34
Joined: Fri Feb 22, 2019 10:05 am

asm file with a dcm sample?

Post by Tompis1995 »

Hello. I'm having a hard time trying to integrate dcm data into a single asm file. If I put raw DPCM samples extracted from a Famtracker file into the RODATA section, what are the parameters needed for the NES to convert them to sound? Thanks!
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: asm file with a dcm sample?

Post by Memblers »

Here are excerpts from my speech synth. The data being input through (speech_lo),y is one byte speed select, next byte sample number. Kinda dumb that I used words for the lookup tables though, could have been like .byte <((voc00-$C000)/$40). You need to write $4010,$4011,$4012,$4013 and $4015. The sample(s) need to be at $C000 or higher, and they should begin on a 64 byte boundary.

Code: Select all

        ldy #0
        lda (speech_lo),y
        ora #%10000000
        sta $4010
        lda #$40
        sta $4011

        iny
        lda (speech_lo),y

        asl
        tax

        lda sample_length_index,x
        sta $4013
        lda sample_addr_index,x
        sta $4012

        lda #%00010000
        sta $4015
        

sample_addr_index:

         .word (voc00-$C000)/$40
         .word (voc01-$C000)/$40
         .word (voc02-$C000)/$40
         
sample_length_index:

        .word (voc01-voc00)/16  ; a
        .word (voc02-voc01)/16  ; ae
        .word (voc03-voc02)/16  ; aw
        
.segment "SAMPLES"              ; $C000 - $FFF9

voc00:  .incbin "set1\a.dmc"
voc01:  .incbin "set1\ae.dmc"
voc02:  .incbin "set1\aw.dmc"       
 
Sounds like you're using ca65, If you post your linker config, that would help.
Tompis1995
Posts: 34
Joined: Fri Feb 22, 2019 10:05 am

Re: asm file with a dcm sample?

Post by Tompis1995 »

Memblers wrote: Sun Jan 02, 2022 11:19 pm Here are excerpts from my speech synth. The data being input through (speech_lo),y is one byte speed select, next byte sample number. Kinda dumb that I used words for the lookup tables though, could have been like .byte <((voc00-$C000)/$40). You need to write $4010,$4011,$4012,$4013 and $4015. The sample(s) need to be at $C000 or higher, and they should begin on a 64 byte boundary.

Code: Select all

        ldy #0
        lda (speech_lo),y
        ora #%10000000
        sta $4010
        lda #$40
        sta $4011

        iny
        lda (speech_lo),y

        asl
        tax

        lda sample_length_index,x
        sta $4013
        lda sample_addr_index,x
        sta $4012

        lda #%00010000
        sta $4015
        

sample_addr_index:

         .word (voc00-$C000)/$40
         .word (voc01-$C000)/$40
         .word (voc02-$C000)/$40
         
sample_length_index:

        .word (voc01-voc00)/16  ; a
        .word (voc02-voc01)/16  ; ae
        .word (voc03-voc02)/16  ; aw
        
.segment "SAMPLES"              ; $C000 - $FFF9

voc00:  .incbin "set1\a.dmc"
voc01:  .incbin "set1\ae.dmc"
voc02:  .incbin "set1\aw.dmc"       
 
Sounds like you're using ca65, If you post your linker config, that would help.
Can you write the configuration values for "SAMPLES" because the segment doesn't exist in my compilier's cfg file. Also, for the linker config, all I'm using is typing this in command prompt:

Code: Select all

ca65 filename.asm -o filename.o -t nes
ld65 filename.o -o filename.nes -t nes
and finally, what is "speech_lo"? Is it just a variable you would put and tag it with .res 1? Thanks!
User avatar
dougeff
Posts: 3079
Joined: Fri May 08, 2015 7:17 pm

Re: asm file with a dcm sample?

Post by dougeff »

speech_lo...

It looks like a pointer to the data stream. For a pointer to work (mode = indirect indexed with y) you need 2 zeropage variables, the first is the LSB the second is the MSB

.segment "ZEROPAGE"

speech_lo: .res 1
speech_hi: .res 1
nesdoug.com -- blog/tutorial on programming for the NES
Tompis1995
Posts: 34
Joined: Fri Feb 22, 2019 10:05 am

Re: asm file with a dcm sample?

Post by Tompis1995 »

Here's my poorly written asm code (featuring my favorite internet celebrity the Tourette's Guy). Plus the char and the famitracker file. Is there something I'm doing wrong?
Attachments
tourettes guy.chr
(8 KiB) Downloaded 45 times
fuck.ftm
(3.04 KiB) Downloaded 49 times
tourettesguy.asm
(15.45 KiB) Downloaded 46 times
tourettesguy.nes
(72.02 KiB) Downloaded 51 times
User avatar
Memblers
Site Admin
Posts: 4044
Joined: Mon Sep 20, 2004 6:04 am
Location: Indianapolis
Contact:

Re: asm file with a dcm sample?

Post by Memblers »

Using 'ld65 -t nes' has it use its built-in nes.cfg. To use a custom one instead, use 'ld65 -C nes.cfg'. I have added one line to the built-in config to add the SAMPLES segment (I did not test it), save this as 'nes.cfg' (or whatever filename you want) and put it in the same folder as your source files.

Code: Select all

SYMBOLS {
    __STACKSIZE__: type = weak, value = $0300; # 3 pages stack
}
MEMORY {
    ZP:     file = "", start = $0002, size = $001A, type = rw, define = yes;

    # INES Cartridge Header
    HEADER: file = %O, start = $0000, size = $0010, fill = yes;

    # 2 16K ROM Banks
    # - startup
    # - code
    # - rodata
    # - data (load)
    ROM0:   file = %O, start = $8000, size = $7FFA, fill = yes, define = yes;

    # Hardware Vectors at End of 2nd 8K ROM
    ROMV:   file = %O, start = $FFFA, size = $0006, fill = yes;

    # 1 8k CHR Bank
    ROM2:   file = %O, start = $0000, size = $2000, fill = yes;

    # standard 2k SRAM (-zeropage)
    # $0100-$0200 cpu stack
    # $0200-$0500 3 pages for ppu memory write buffer
    # $0500-$0800 3 pages for cc65 parameter stack
    SRAM:   file = "", start = $0500, size = __STACKSIZE__, define = yes;

    # additional 8K SRAM Bank
    # - data (run)
    # - bss
    # - heap
    RAM:    file = "", start = $6000, size = $2000, define = yes;
}
SEGMENTS {
    ZEROPAGE: load = ZP,              type = zp;
    HEADER:   load = HEADER,          type = ro;
    STARTUP:  load = ROM0,            type = ro,  define   = yes;
    LOWCODE:  load = ROM0,            type = ro,  optional = yes;
    ONCE:     load = ROM0,            type = ro,  optional = yes;
    CODE:     load = ROM0,            type = ro,  define   = yes;
    RODATA:   load = ROM0,            type = ro,  define   = yes;
    DATA:     load = ROM0, run = RAM, type = rw,  define   = yes;
	SAMPLES:  load = ROM0, 	  type = ro,  define   = yes,	start = $C000;
    VECTORS:  load = ROMV,            type = rw;
    CHARS:    load = ROM2,            type = rw;
    BSS:      load = RAM,             type = bss, define   = yes;
}
FEATURES {
    CONDES: type    = constructor,
            label   = __CONSTRUCTOR_TABLE__,
            count   = __CONSTRUCTOR_COUNT__,
            segment = ONCE;
    CONDES: type    = destructor,
            label   = __DESTRUCTOR_TABLE__,
            count   = __DESTRUCTOR_COUNT__,
            segment = RODATA;
    CONDES: type    = interruptor,
            label   = __INTERRUPTOR_TABLE__,
            count   = __INTERRUPTOR_COUNT__,
            segment = RODATA,
            import  = __CALLIRQ__;
}
Later on, if you need to make your own config, it can be easier than it looks (without the compiler related stuff in the built-in one). Here's the config I use in my speech program.

Code: Select all

MEMORY {
            ZP: start = $00, size = $100, type = rw;
            RAM: start = $200, size = $600, type = rw;
            WRAM: start = $6000, size = $2000, type = rw;
            PRG: start = $8000, size = $8000, type = ro, file = %O;
        }
        SEGMENTS {
            CODE: load = PRG, type = ro, start = $8000;
            RODATA: load = PRG, type = ro;
            DATA: load = RAM, type = bss;
            WRAM: load = WRAM, type = rw;
            ZEROPAGE: load = ZP, type = zp;
            BSS: load = RAM, type = bss, define = yes;
            SAMPLES: load = PRG, type = ro, start = $C000;
            VECTORS: load = PRG, type = ro, start = $FFFA;
        }
Going for something simple, if you want to just play the one sample, forget about the lda (speech_lo),y stuff. Instead, we can try something like this:

Code: Select all

produceFuckSound:
ldy #$00
lda #$0F ; $00-$0F are playback speeds
sta $4010
lda #$40
sta $4011
lda #<((dmc_fuck_end - dmc_fuck) / 16)
sta $4013
lda #<((dmc_fuck - $C000) / 64)
sta $4012
lda #%00010000
sta $4015
rts

.segment "SAMPLES"
dmc_fuck:
.incbin "fuck.dmc"
dmc_fuck_end:

Tompis1995
Posts: 34
Joined: Fri Feb 22, 2019 10:05 am

Re: asm file with a dcm sample?

Post by Tompis1995 »

Memblers wrote: Tue Jan 04, 2022 3:57 am Using 'ld65 -t nes' has it use its built-in nes.cfg. To use a custom one instead, use 'ld65 -C nes.cfg'. I have added one line to the built-in config to add the SAMPLES segment (I did not test it), save this as 'nes.cfg' (or whatever filename you want) and put it in the same folder as your source files.

Code: Select all

SYMBOLS {
    __STACKSIZE__: type = weak, value = $0300; # 3 pages stack
}
MEMORY {
    ZP:     file = "", start = $0002, size = $001A, type = rw, define = yes;

    # INES Cartridge Header
    HEADER: file = %O, start = $0000, size = $0010, fill = yes;

    # 2 16K ROM Banks
    # - startup
    # - code
    # - rodata
    # - data (load)
    ROM0:   file = %O, start = $8000, size = $7FFA, fill = yes, define = yes;

    # Hardware Vectors at End of 2nd 8K ROM
    ROMV:   file = %O, start = $FFFA, size = $0006, fill = yes;

    # 1 8k CHR Bank
    ROM2:   file = %O, start = $0000, size = $2000, fill = yes;

    # standard 2k SRAM (-zeropage)
    # $0100-$0200 cpu stack
    # $0200-$0500 3 pages for ppu memory write buffer
    # $0500-$0800 3 pages for cc65 parameter stack
    SRAM:   file = "", start = $0500, size = __STACKSIZE__, define = yes;

    # additional 8K SRAM Bank
    # - data (run)
    # - bss
    # - heap
    RAM:    file = "", start = $6000, size = $2000, define = yes;
}
SEGMENTS {
    ZEROPAGE: load = ZP,              type = zp;
    HEADER:   load = HEADER,          type = ro;
    STARTUP:  load = ROM0,            type = ro,  define   = yes;
    LOWCODE:  load = ROM0,            type = ro,  optional = yes;
    ONCE:     load = ROM0,            type = ro,  optional = yes;
    CODE:     load = ROM0,            type = ro,  define   = yes;
    RODATA:   load = ROM0,            type = ro,  define   = yes;
    DATA:     load = ROM0, run = RAM, type = rw,  define   = yes;
	SAMPLES:  load = ROM0, 	  type = ro,  define   = yes,	start = $C000;
    VECTORS:  load = ROMV,            type = rw;
    CHARS:    load = ROM2,            type = rw;
    BSS:      load = RAM,             type = bss, define   = yes;
}
FEATURES {
    CONDES: type    = constructor,
            label   = __CONSTRUCTOR_TABLE__,
            count   = __CONSTRUCTOR_COUNT__,
            segment = ONCE;
    CONDES: type    = destructor,
            label   = __DESTRUCTOR_TABLE__,
            count   = __DESTRUCTOR_COUNT__,
            segment = RODATA;
    CONDES: type    = interruptor,
            label   = __INTERRUPTOR_TABLE__,
            count   = __INTERRUPTOR_COUNT__,
            segment = RODATA,
            import  = __CALLIRQ__;
}
Later on, if you need to make your own config, it can be easier than it looks (without the compiler related stuff in the built-in one). Here's the config I use in my speech program.

Code: Select all

MEMORY {
            ZP: start = $00, size = $100, type = rw;
            RAM: start = $200, size = $600, type = rw;
            WRAM: start = $6000, size = $2000, type = rw;
            PRG: start = $8000, size = $8000, type = ro, file = %O;
        }
        SEGMENTS {
            CODE: load = PRG, type = ro, start = $8000;
            RODATA: load = PRG, type = ro;
            DATA: load = RAM, type = bss;
            WRAM: load = WRAM, type = rw;
            ZEROPAGE: load = ZP, type = zp;
            BSS: load = RAM, type = bss, define = yes;
            SAMPLES: load = PRG, type = ro, start = $C000;
            VECTORS: load = PRG, type = ro, start = $FFFA;
        }
Going for something simple, if you want to just play the one sample, forget about the lda (speech_lo),y stuff. Instead, we can try something like this:

Code: Select all

produceFuckSound:
ldy #$00
lda #$0F ; $00-$0F are playback speeds
sta $4010
lda #$40
sta $4011
lda #<((dmc_fuck_end - dmc_fuck) / 16)
sta $4013
lda #<((dmc_fuck - $C000) / 64)
sta $4012
lda #%00010000
sta $4015
rts

.segment "SAMPLES"
dmc_fuck:
.incbin "fuck.dmc"
dmc_fuck_end:

Ah! There we go! Thank ye! It worked!
Post Reply