Jump to content
IGNORED

CDFJ audio/waveforms/envelopes


Andrew Davie

Recommended Posts

Can someone point me towards some documentation on CDFJ capability (and examples...?) for CDFJ audio streaming.  Particularly the "3 channels" that I've seen alluded to. I have some decent "normal" music playing in my game (envelope-based) but would like to see how CDFJ/streaming could improve this.

Link to comment
Share on other sites

  • 2 weeks later...

Hmm, apparently I'd neglected to "follow" the Harmony/Melody club, so was unaware of your request until today. That's been rectified.

 

We have a simple music, and a simple speech demo, used for testing the CDFJ driver as we made changes to it. I'll track down the most current versions and post them later today.

 

I also ported the music driver from Stay Frosty 2 to CDFJ for John to use in Mappy. It does on-the-fly manipulation of the waveforms to generate ADSR. I'll track that down and post it as well.

  • Like 1
Link to comment
Share on other sites

3 minutes ago, SpiceWare said:

Hmm, apparently I'd neglected to "follow" the Harmony/Melody club, so was unaware of your request until today. That's been rectified.

 

We have a simple music, and a simple speech demo, used for testing the CDFJ driver as we made changes to it. I'll track down the most current versions and post them later today.

 

I also ported the music driver from Stay Frosty 2 to CDFJ for John to use in Mappy. It does on-the-fly manipulation of the waveforms to generate ADSR. I'll track that down and post it as well.

TY.  I have ADSR in my own effort, but it's not using streams; just 60Hz manipulation of AUDV from hardwired ADSR envelopes, using preset AUDC/AUDF.  First time I've ever done anything music related, so I'm on a steep learning curve. It does a surprisingly "good" job of simulating different instruments, though, rudimentary as it is. I'll PM you the latest to have a listen to.  I'm somewhat bad at audio stuff, as my ears are nowhere near even slightly capable of hearing this stuff properly.

Link to comment
Share on other sites

CDFJ music demo

 

cdfj_music.zip

 

When using Music Mode the CDFJ driver supports playing back 3 voice music similar to the music in Pitfall 2.  Unlike Pitfall 2's square waves only, CDFJ supports custom waveforms for a wider variety of sounds. Examples of this can be heard in Stay Frosty 2 and Mappy. Note: while SF2 uses the DPC+ driver, the ARM enhanced audio is basically the same as when using the CDFJ driver. The music only uses TIA's voice 0, voice 1 is available for your game's sound effects.

 

In your 6507 code

  • Set the mode to music
  • update AUDV0 once per scanline
  • call your ARM routines with Audio Interrupt turned on

 

In your ARM code:

  • Copy the waveforms from ROM into Display Data RAM
  • call setWaveform() for each voice
  • call setNote() for each voice

 

6507 code

 

Set the mode to music

 

When updating SETMODE make sure to use the AUDIOMUSIC constant:

 

    ldx #AUDIOMUSIC|FASTON
    stx SETMODE

 

 

update AUDV0 once per scanline

 

Read from AMPLITUDE and update AUDV0 once per scanline. For best audio quality do the update on the same cycle on every scanline, though this is not always possible.

 

    lda #AMPLITUDE
    sta AUDV0

 

NOTE: lda #AMPLITUDE requires SETMODE to have been set with FASTON constant.

 

WARNING: Do NOT do this, you cannot "read ahead" from AMPLITUDE

 

    lda #AMPLITUDE
    ... any other 6507 code
    sta AUDV0

 

 

call your ARM routines with Audio Interrupt turned on

 

When calling your ARM routines you will want to turn on the Audio Interrupt so the updates to AUDV0 will still occur about once per scanline.

 

    ldx #$FE            ; Run ARM code with digital audio interrupt
    stx CALLFN          ; Call Function

 

The $FE tells CALLFN to trigger an ARM interrupt about once per scanline. The interrupt routine will calculate the current audio value, then output this sequence to the 6507's bus:

    LDX #value
    STX AUDV0
    NOP

 

And yes, this means the value in the 6507's X register will no longer be $FE after stx CALLFN has finished executing.

 

NOTE: Using the audio interrupt will cause about a 10% hit in performance for your C code.

 

 

ARM code

 

Copy the waveforms from ROM into Display Data RAM

 

For CDFJ driver performance reasons the waveforms must be located in RAM.  The waveforms also need to be aligned on 32 byte boundaries. Search for "Waveform Tables" in cdf1_music.asm for more info and example waveforms.

 

 

call setWaveform() for each voice

 

C function setWaveform(voice, waveform), located in defines_cdfj.h, is used to set the waveform buffer used by each voice.  

  • voice = 0 - 2
  • waveform = which 32 byte waveform buffer.  Basically the address offset into Display Data / 32.

 

call setNote() for each voice

 

C function setNote(voice, frequency), located in defines_cdfj.h, is used to set the frequency of each voice.

  • voice = 0 - 2
  • frequency = frequency of the note. Use getPitch(note) , located in defines_cdfj.h, to calculate the frequency. note = 1-88 where 1 = A0 and 88 = C7

 

While the waveforms default to 32 bytes in size, you can change that using setWaveSize(voice, size), also located in defines_cdfj.h. I don't believe anybody has used this feature yet.

 

  • Thanks 1
Link to comment
Share on other sites

31 minutes ago, bithopper said:

Couldn't resist playing around with your danube song ...

 

Actually @cd-w's song. He also used it when experimenting with the DPC's music abilities back in 2010:

 

 

 

I also did a DPC experiment around the same time frame, though mine was with graphics:

 

 

Our experiments with the Harmony's support for DPC lead to the creation of DPC+, and eventually CDFJ.

 

Quote

some experiment with dynamic wave forms for the lead voice.

 Fun!

Link to comment
Share on other sites

CDFJ speech demo (sample playback)

 

cdfj_speech.zip

 

When using Sample Mode the CDFJ driver supports playing back digital audio samples. Examples of this can be heard in Draconian. The samples only uses TIA's voice 0, voice 1 is available for your game's sound effects. If you're creative, you can still use voice 0 for sound effects whenever a sample is not playing. This also can be heard in Draconian.

 
In your 6507 code

  • Set the mode to sample
  • update AUDV0 once per scanline
  • call your ARM routines with Audio Interrupt turned on

In your ARM code:

  • Start sample
  • Test for end of sample

6507 code

 

Set the mode to sample

 

When updating SETMODE make sure to use the AUDIOSAMPLE constant:

 

    ldx #AUDIOSAMPLE|FASTON
    stx SETMODE


update AUDV0 once per scanline

 

Read from AMPLITUDE and update AUDV0 once per scanline. For best audio quality do the update on the same cycle on every scanline, though this is not always possible.

 

    lda #AMPLITUDE
    sta AUDV0

 

NOTE: lda #AMPLITUDE requires SETMODE to have been set with FASTON constant.

 

WARNING: Do NOT do this, you cannot "read ahead" from AMPLITUDE

 

    lda #AMPLITUDE
    ... any other 6507 code
    sta AUDV0

 


call your ARM routines with Audio Interrupt turned on

 


When calling your ARM routines you will want to turn on the Audio Interrupt so the updates to AUDV0 will still occur about once per scanline.
 

    ldx #$FE            ; Run ARM code with digital audio interrupt
    stx CALLFN          ; Call Function

 
The $FE tells CALLFN to trigger an ARM interrupt about once per scanline. The interrupt routine will extract the next sample value, then output this sequence to the 6507's bus:

 

    LDX #value
    STX AUDV0
    NOP

 
And yes, this means the value in the 6507's X register will no longer be $FE after stx CALLFN has finished executing.
 
NOTE: Using the audio interrupt will cause about a 10% hit in performance for your C code.

 

ARM code

 

 

Start sample

 

To start a sample reset the sample to the beginning, set the playback rate, and set the pointer to the sample's position.

 

    resetWave(0);
    setNote(0, rate);
    setNote(1, 0);
    setNote(2, 0);
    setSamplePtr(sample);

 

 

 

Stop playback at end of sample

 

Retrieve getWavePtr(0) to get the current playback position of the sample. Once end has been reached then stop playback (or start a new sample).

 

 

  if (sample_size > getWavePtr(0) >> 21)
  {
    // if sample has been fully played stop playback
    setNote(0, 0);
    resetWave(0);
  }

 

 

 

Sample info

 

Samples are 4 bit values, which are packed 2 per byte.   Upper nybble of the byte is played back before the lower nybble. Max size of the packed sample data is 2K - which is 4096 sample values when the bytes are split into nybbles for playback.

 

This C utility will convert a raw 8-bit audio file to the packed format. A raw file means there's no header information in the file, just digital samples.

raw_to_dpc.c

 

I used SOX to create raw 8-bit audio files.

 

Link to comment
Share on other sites

I've tracked down the Stay Frosty 2 music driver I ported for John for Mappy. It's using an old version of the CDF driver, so I'll need to update it to CDFJ before posting it.

 

On 1/1/2023 at 6:20 PM, SpiceWare said:

Using the audio interrupt will cause about a 10% hit in performance for your C code.

 

In regards to this, the performance hit is less than 10%.  Your custom ARM code is idled once per scanline for this sequence of 6507 opcodes:

  • 0-2 cycles waiting for the currently executing NOP to finish
  • 2 cycles for LDX #value
  • 3 cycles for STX AUDV0
  • 0 cycles for NOP - custom ARM code resumes after putting this NOP on the bus

For 5 - 7 cycles of run time per scanline, which is 6.6% - 9.2%, or a 7.9% performance hit on average.

 

There's also a slight amount of time spent calculating the audio value, but its minuscule in comparison to the time it takes the 6507 to run those opcodes, so we could say about an 8% hit on average.

 

 

  • Thanks 1
Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...