Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rework audio wave channel #562

Merged
merged 1 commit into from
Jan 25, 2021
Merged

Conversation

Daft-Freak
Copy link
Collaborator

  • Rename the callback for more consistency (Random API inconsistencies #344)
  • Pass the channel to the callback, helps if you're using more than one channel... and just makes sense
  • Stop doing << 8 on samples. Now you can use 16-bit samples without reducing the volume 256x
  • Make the callback optional to allow using a fixed pattern.
  • wave_callback_arg is now a generic user_data pointer.

Changes for users are...

Old:

channels[0].wave_callback_arg = some_ptr;
channels[0].callback_waveBufferRefresh = &callback;

//...

void callback(void *data) {
  //...
  for(int i = 0; i < 64; i++)
    channels[0].wave_buffer[i] = some_sample;
}

New:

channels[0].user_data = some_ptr;
channels[0].wave_buffer_callback = &callback;

//...

void callback(AudioChannel &channel) {
  auto data = channel->user_data;
  //...
  for(int i = 0; i < 64; i++)
    channel.wave_buffer[i] = some_sample;
}

Also, if you're using 8-bit samples you need to multiply them by 256 now. (If you're using 16-bit samples you can stop dividing your volume by 256).

This will also cause API breakage, but will only affect games that use the WAVE waveform (callback arg will be wrong).

- Rename the callback for more consistency
- Pass the channel to the callback
- Stop doing << 8 on samples
- Make the callback optional
@zenodante
Copy link
Contributor

Should we also make some short playback buffer on 32blit hardware instead of generating 1 sample per interupt? Currently a 22k Hz interrupt for sound system is too frequent. A ~50Hz interupt for filling playback DMA call would make the sound playback more accurate and stable.

@Gadgetoid
Copy link
Contributor

@zenodante probably - yes - although we'd need - I guess - to size the wave buffer appropriately (441 samples?) and the output buffer appropriately.

IIRC an earlier build I had a buffer set up with a memory -> peripheral DMA, and would run the audio engine on the DMA-half-complete callback.

My reasoning for switching to a 22050Hz native sample rate with the audio engine invoked on every sample (IIRC) is due to wanting to mirror the capabilities of retro audio engines in the hands of expert composers. IE: you can mash the audio channel settings at high frequencies to create new effects and sounds that the sound system designer may not have anticipated.

That said I'm not sure this is how - for example - the more advanced C64 SID tunes actually worked. Is a 50Hz "Vblank" interrupt equivalent actually... fine?

This then begs the question- how does the end-user control the audio engine. If we're dealing with a sample buffer and a 50Hz update rate then a majority of changes to the engine in update would be moot. You'd almost have to treat audio like a render operation and do it there... maybe that's okay?

@Daft-Freak
Copy link
Collaborator Author

Currently you can only really have 100Hz updates anyway. You could try to do precise timing within update, but not really between updates since there's all the input/i2c/usb stuff going on there...

(I guess for more advanced stuff you'd want the game to be able to refill the output buffer directly, instead of using a single WAVE channel and a double-copy.)

@zenodante
Copy link
Contributor

@zenodante probably - yes - although we'd need - I guess - to size the wave buffer appropriately (441 samples?) and the output buffer appropriately.

IIRC an earlier build I had a buffer set up with a memory -> peripheral DMA, and would run the audio engine on the DMA-half-complete callback.

My reasoning for switching to a 22050Hz native sample rate with the audio engine invoked on every sample (IIRC) is due to wanting to mirror the capabilities of retro audio engines in the hands of expert composers. IE: you can mash the audio channel settings at high frequencies to create new effects and sounds that the sound system designer may not have anticipated.

That said I'm not sure this is how - for example - the more advanced C64 SID tunes actually worked. Is a 50Hz "Vblank" interrupt equivalent actually... fine?

This then begs the question- how does the end-user control the audio engine. If we're dealing with a sample buffer and a 50Hz update rate then a majority of changes to the engine in update would be moot. You'd almost have to treat audio like a render operation and do it there... maybe that's okay?

If we use the timer event to provide the DMA tick and use double buffer for DMA transfer to DAC, we could set the buffer size to any number you would like. 100 means (22050/100 = 220.5 hz buffer update rate) and we will call the sound generation function 100 times to fill the next buffer in interrupt. As the buffer refreashing is done in the DMA finished interrupt, user would not notice any difference. (Just like Daft Freak mentioned, user could only update the channel statement in less than ~100Hz)

It would reduce the interrupt frequency, increase system performance and make the code more I-cache friendly. (Otherwise the sound signal function would be moved into I-cache 22k times per second and replaced by game code after return back from interrupt)

@Daft-Freak
Copy link
Collaborator Author

Hmm, you can use the callback on a WAVE channel as as fast-ish timer to mess with audio stuff...

Anyway, using a buffer or not for the output wouldn't really affect this PR as it's just changing the user-visible part. (and SDL already works like that...)

@Gadgetoid Gadgetoid merged commit 0435903 into 32blit:master Jan 25, 2021
@Gadgetoid
Copy link
Contributor

True, getting hung up on a separate issue here- discussion can continue here -> #568

Gadgetoid added a commit to Gadgetoid/32BlitDoom that referenced this pull request Jan 27, 2021
Gadgetoid added a commit to Gadgetoid/32BlitDoom that referenced this pull request Jan 27, 2021
Gadgetoid added a commit to Gadgetoid/32BlitDoom that referenced this pull request Jan 27, 2021
Daft-Freak pushed a commit to Daft-Freak/32BlitDoom that referenced this pull request Jan 28, 2021
@Daft-Freak Daft-Freak deleted the break-all-the-audio branch February 13, 2021 15:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants