CDROM checkpoint, hacky AdLib

This commit is contained in:
Ian Scott committed 2025-06-12 23:10:52 -06:00
1 parent f6cf314a63
commit d0df0cdd42
9 files changed
+117 -103

No files matched your search

+1 -1
View File
@@ -77,7 +77,7 @@ static const char *modenames[9] = {
#define MODE_CDPORT 0x60 // CD base port
#define MODE_CDSTATUS 0x61 // Get CD image command status
#define MODE_CDIMAGES 0x62 // List CD images
#define MODE_CDLIST 0x62 // List CD images
#define MODE_CDLOAD 0x63 // Load CD image or get loaded image
#define MODE_CDSELECT 0x64 // Select next/prev loaded image
+17 -2
View File
@@ -242,7 +242,7 @@ static bool print_cdimage_list(void) {
uint8_t current_index = inp(DATA_PORT_HIGH);
printf("Listing CD images on USB drive:\n");
outp(CONTROL_PORT, 0xCC); // Knock on the door...
outp(CONTROL_PORT, MODE_CDIMAGES); // Select CD image list register
outp(CONTROL_PORT, MODE_CDLIST); // Select CD image list register
delay(10);
outp(CONTROL_PORT, 0xCC); // Knock on the door...
outp(CONTROL_PORT, MODE_CDSTATUS); // Select CD image status register
@@ -262,7 +262,7 @@ static bool print_cdimage_list(void) {
return false;
}
outp(CONTROL_PORT, 0xCC); // Knock on the door...
outp(CONTROL_PORT, MODE_CDIMAGES); // Select CD image list register
outp(CONTROL_PORT, MODE_CDLIST); // Select CD image list register
char b[256], c, *p = b;
uint8_t line = 1;
while ((c = inp(DATA_PORT_HIGH)) != 4 /* ASCII EOT */) {
@@ -283,6 +283,21 @@ static bool print_cdimage_list(void) {
}
static void print_cdimage_current(void) {
outp(CONTROL_PORT, 0xCC); // Knock on the door...
outp(CONTROL_PORT, MODE_FWSTRING); // Select firmware string register
char firmware_string[256] = {0};
for (uint8_t i = 0; i < 255; ++i) {
firmware_string[i] = inp(DATA_PORT_HIGH);
if (!firmware_string[i]) {
break;
}
}
printf("Firmware version: %s\n", firmware_string);
}
static void write_settings(void) {
outp(CONTROL_PORT, MODE_SAVE); // Select save settings register
outp(DATA_PORT_HIGH, 0xff);
+2
View File
@@ -61,6 +61,7 @@ add_compile_definitions(
PICO_DEFAULT_UART=0
PICO_DEFAULT_UART_TX_PIN=28
PICO_DEFAULT_UART_RX_PIN=-1
PICO_DEFAULT_UART_BAUD_RATE=230400
PICO_STDIO_USB_CONNECT_WAIT_TIMEOUT_MS=250
)
@@ -234,6 +235,7 @@ function(build_sb TARGET_NAME MULTIFW)
SOUND_SB=1
SOUND_DSP=1
CDROM=1
# SB_BUFFERLESS=1
)
target_sources(${TARGET_NAME} PRIVATE
${PICO_TINYUSB_PATH}/lib/fatfs/source/ff.c
+1 -1
View File
@@ -424,7 +424,7 @@ void cdrom_audio_fifo_init(cdrom_t *dev) {
fifo_init(&dev->audio_fifo);
}
bool cdrom_audio_callback(cdrom_t *dev, uint32_t len) { // len is int
bool cdrom_audio_callback(cdrom_t *dev, uint32_t len) {
bool ret = true;
if (dev->cd_status != CD_STATUS_PLAYING) {
+17 -8
View File
@@ -36,8 +36,8 @@
extern cdrom_t cdrom[CDROM_NUM];
//------------- Elm Chan FatFS -------------//
static FATFS fatfs[CFG_TUH_DEVICE_MAX]; // for simplicity only support 1 LUN per device
static volatile bool _disk_busy[CFG_TUH_DEVICE_MAX];
static FATFS fatfs[CDROM_NUM]; // for simplicity only support 1 device
static volatile bool _disk_busy[CDROM_NUM];
// define the buffer to be place in USB/DMA memory with correct alignment/cache line size
CFG_TUH_MEM_SECTION static struct {
@@ -47,7 +47,7 @@ CFG_TUH_MEM_SECTION static struct {
bool msc_app_init(void)
{
for(size_t i=0; i<CFG_TUH_DEVICE_MAX; i++) {
for(size_t i=0; i<CDROM_NUM; i++) {
_disk_busy[i] = false;
}
@@ -106,7 +106,7 @@ static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const
return false;
}
cdman_set_serial(serial);
/* cdman_load_image_index(&cdrom[0], 1); */
cdman_load_image_index(&cdrom[drive_num], 1);
return true;
}
@@ -115,7 +115,11 @@ static bool inquiry_complete_cb(uint8_t dev_addr, tuh_msc_complete_data_t const
void tuh_msc_mount_cb(uint8_t dev_addr)
{
printf("A MassStorage device is mounted\r\n");
if (dev_addr > 1) {
// Only handle a single drive for now
printf("Only a single USB drive is supported\n");
return;
}
uint8_t const lun = 0;
tuh_msc_inquiry(dev_addr, lun, &scsi_resp.inquiry, inquiry_complete_cb, 0);
}
@@ -123,6 +127,11 @@ void tuh_msc_mount_cb(uint8_t dev_addr)
void tuh_msc_umount_cb(uint8_t dev_addr)
{
printf("A MassStorage device is unmounted\r\n");
if (dev_addr > 1) {
// Only handle a single drive for now
printf("Only a single USB drive is supported\n");
return;
}
uint8_t const drive_num = dev_addr-1;
char drive_path[3] = "0:";
@@ -130,11 +139,11 @@ void tuh_msc_umount_cb(uint8_t dev_addr)
f_unmount(drive_path);
cdman_unload_image(&cdrom[0]);
cdman_unload_image(&cdrom[drive_num]);
// if ( phy_disk == f_get_current_drive() )
// { // active drive is unplugged --> change to other drive
// for(uint8_t i=0; i<CFG_TUH_DEVICE_MAX; i++)
// for(uint8_t i=0; i<CDROM_NUM; i++)
// {
// if ( disk_is_ready(i) )
// {
@@ -248,5 +257,5 @@ DRESULT disk_ioctl (
return RES_PARERR;
}
return RES_OK;
return RES_OK;
}
-26
View File
@@ -281,32 +281,6 @@ void MKE_WRITE(uint16_t address, uint8_t value) {
case 1:
mke.data_select=value;
break;
/*
case 2:
switch(value) {
case 1:
sprintf(cdrom[0].image_path,"MECH2_16B.CUE");
break;
case 2:
sprintf(cdrom[0].image_path,"descent-ii.cue");
break;
case 3:
sprintf(cdrom[0].image_path,"Loom (USA).cue");
break;
case 4:
sprintf(cdrom[0].image_path,"MYST.cue");
break;
case 5:
sprintf(cdrom[0].image_path,"megarace.iso");
break;
default:
sprintf(cdrom[0].image_path,"");
break;
}
cdrom[0].req_command = CD_COMMAND_IMAGE_LOAD;
printf("loaded %s\n", cdrom[0].image_path);
break;
*/
case 3:
mke.enable_register=value;
break;
+25 -8
View File
@@ -51,7 +51,7 @@ psram_spi_inst_t* async_spi_inst;
// UART_TX_PIN is defined in isa_io.pio.h
#define UART_RX_PIN (-1)
#define UART_ID uart0
#define BAUD_RATE 115200
#define BAUD_RATE 230400
uint LED_PIN;
@@ -69,9 +69,10 @@ extern void sbdsp_process();
#include "opl.h"
void play_adlib(void);
extern "C" int OPL_Pico_Init(unsigned int);
extern "C" void OPL_Pico_PortWrite(opl_port_t, unsigned int);
extern "C" unsigned int OPL_Pico_PortRead(opl_port_t);
#include "cmd_buffers.h"
cms_buffer_t opl_buffer = { {0}, 0, 0 };
// #include "cmd_buffers.h"
// cms_buffer_t opl_buffer = { {0}, 0, 0 };
#endif
#ifdef CDROM
@@ -223,7 +224,7 @@ __force_inline void select_picogus(uint8_t value) {
break;
case MODE_CDSTATUS:
break;
case MODE_CDIMAGES:
case MODE_CDLIST:
#ifdef CDROM
if (cdrom[0].image_status != CD_STATUS_READY) {
cdrom[0].image_status = CD_STATUS_BUSY;
@@ -519,7 +520,7 @@ __force_inline uint8_t read_picogus_high(void) {
case MODE_CDSTATUS:
printf("cdstatus %x\n", cdrom[0].image_status);
return cdrom[0].image_status;
case MODE_CDIMAGES:
case MODE_CDLIST:
if (cur_read_idx == cdrom[0].image_count) { // If end of the images
cur_read_idx = cur_read = 0;
cdrom[0].image_status = CD_STATUS_IDLE;
@@ -632,16 +633,21 @@ __force_inline void handle_iow(void) {
if ((port >> 4) == sb_port_test) {
switch (port - settings.SB.basePort) {
// OPL ports
case 0x8:
case 0x8 ... 0x9:
// Fast write
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
// pio_sm_put(pio0, IOW_PIO_SM, IO_END);
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
/*
opl_buffer.cmds[opl_buffer.head++] = {
OPL_REGISTER_PORT,
(uint8_t)(iow_read & 0xFF)
};
// Fast write - return early as we've already written 0x0u to the PIO
return;
*/
OPL_Pico_PortWrite((opl_port_t)(port & 1), (uint8_t)(iow_read & 0xFF));
break;
/*
case 0x9:
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
opl_buffer.cmds[opl_buffer.head++] = {
@@ -649,6 +655,7 @@ __force_inline void handle_iow(void) {
(uint8_t)(iow_read & 0xFF)
};
break;
*/
// DSP ports
default:
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
@@ -667,7 +674,8 @@ __force_inline void handle_iow(void) {
} else // if follows down below
#endif
#if defined(SOUND_OPL)
if (port == settings.SB.oplBasePort) {
if ((port & 0x3fe) == settings.SB.oplBasePort) {
/*
// Fast write
pio_sm_put(pio0, IOW_PIO_SM, IO_END);
opl_buffer.cmds[opl_buffer.head++] = {
@@ -676,6 +684,10 @@ __force_inline void handle_iow(void) {
};
// Fast write - return early as we've already written 0x0u to the PIO
return;
*/
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
OPL_Pico_PortWrite((opl_port_t)(port & 1), (uint8_t)(iow_read & 0xFF));
/*
} else if (port == settings.SB.oplBasePort + 1) {
pio_sm_put(pio0, IOW_PIO_SM, IO_WAIT);
if (settings.SB.oplSpeedSensitive) {
@@ -685,6 +697,7 @@ __force_inline void handle_iow(void) {
OPL_DATA_PORT,
(uint8_t)(iow_read & 0xFF)
};
*/
} else // if follows down below
#endif // SOUND_OPL
#ifdef SOUND_TANDY
@@ -820,10 +833,12 @@ __force_inline void handle_ior(void) {
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
switch (port - settings.SB.basePort) {
case 0x8:
/*
// wait for OPL buffer to process
while (opl_buffer.tail != opl_buffer.head) {
tight_loop_contents();
}
*/
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | OPL_Pico_PortRead(OPL_REGISTER_PORT));
break;
default:
@@ -846,10 +861,12 @@ __force_inline void handle_ior(void) {
if (port == settings.SB.oplBasePort) {
// Tell PIO to wait for data
pio_sm_put(pio0, IOR_PIO_SM, IO_WAIT);
/*
// wait for OPL buffer to process
while (opl_buffer.tail != opl_buffer.head) {
tight_loop_contents();
}
*/
pio_sm_put(pio0, IOR_PIO_SM, IOR_SET_VALUE | OPL_Pico_PortRead(OPL_REGISTER_PORT));
} else // if follows down below
#endif
+33 -20
View File
@@ -71,6 +71,7 @@ static dma_inst_t dma_config;
#define DSP_MIDI_WRITE_POLL 0x38
#define DSP_SET_TIME_CONSTANT 0x40
#define DSP_DMA_PAUSE 0xD0
#define DSP_EXIT_DMA_8 0xDA
#define DSP_DAC_PAUSE_DURATION 0x80 // Pause DAC for a duration, then generate an interrupt. Used by Tyrian.
#define DSP_ENABLE_SPEAKER 0xD1
#define DSP_DISABLE_SPEAKER 0xD3
@@ -132,11 +133,15 @@ typedef struct sbdsp_t {
uint8_t reset_state;
#ifdef SB_BUFFERLESS
volatile int16_t cur_sample;
#endif
} sbdsp_t;
static sbdsp_t sbdsp;
#ifndef SB_BUFFERLESS
// uint16_t sbdsp_fifo_level() {
// if(sbdsp.dma_buffer_tail < sbdsp.dma_buffer_head) return DSP_DMA_FIFO_SIZE - (sbdsp.dma_buffer_head - sbdsp.dma_buffer_tail);
// return sbdsp.dma_buffer_tail - sbdsp.dma_buffer_head;
@@ -148,23 +153,6 @@ bool __force_inline sbdsp_fifo_half() {
return false;
}
*/
static int16_t __force_inline dma_interval_trim() {
uint32_t level = fifo_level(&sbdsp.audio_fifo);
// if (level >= (AUDIO_FIFO_SIZE >> 1)) {
/*
if (level >= 768) {
// putchar('+');
return sbdsp.dma_interval_trim;
// return sbdsp.dma_interval_trim;
} else {
// putchar('-');
return -sbdsp.dma_interval_trim;
}
*/
// return (int32_t)(level >> 4) - 32;
// if(sbdsp_fifo_level() >= (DSP_DMA_FIFO_SIZE/2)) return true;
// return false;
}
static int16_t __force_inline dma_interval_calc() {
uint32_t level = fifo_level(&sbdsp.audio_fifo);
if (level < 512) {
@@ -281,6 +269,7 @@ uint16_t sbdsp_fifo_tx(char *buffer, uint16_t len) {
return 0;
}
*/
#endif
static uint32_t DSP_DMA_EventHandler(Bitu val);
static PIC_TimerEvent DSP_DMA_Event = {
@@ -290,17 +279,22 @@ static PIC_TimerEvent DSP_DMA_Event = {
static __force_inline void sbdsp_dma_disable() {
sbdsp.dma_enabled=false;
PIC_RemoveEvent(&DSP_DMA_Event);
// fifo_set_state(&sbdsp.audio_fifo, FIFO_STATE_STOPPED);
#ifdef SB_BUFFERLESS
sbdsp.cur_sample = 0; // zero current sample
#else
// fifo_set_state(&sbdsp.audio_fifo, FIFO_STATE_STOPPED);
#endif
// putchar('S');
}
static __force_inline void sbdsp_dma_enable() {
if(!sbdsp.dma_enabled) {
// sbdsp_fifo_clear();
sbdsp.dma_enabled=true;
PIC_AddEvent(&DSP_DMA_Event, sbdsp.dma_interval, 0);
#ifndef SB_BUFFERLESS
// sbdsp_fifo_clear();
fifo_set_state(&sbdsp.audio_fifo, FIFO_STATE_RUNNING);
#endif
}
// else {
// printf("INFO: DMA Already Enabled");
@@ -312,8 +306,12 @@ static uint32_t DSP_DMA_EventHandler(Bitu val) {
uint32_t current_interval;
sbdsp.dma_sample_count_rx++;
#ifdef SB_BUFFERLESS
current_interval = sbdsp.dma_interval;
#else
// current_interval = sbdsp.dma_interval + dma_interval_trim();
current_interval = dma_interval_calc();
#endif
// printf("%u\n", current_interval);
if(sbdsp.dma_sample_count_rx <= sbdsp.dma_sample_count) {
@@ -333,8 +331,11 @@ static uint32_t DSP_DMA_EventHandler(Bitu val) {
static void sbdsp_dma_isr(void) {
const uint32_t dma_data = DMA_Complete_Write(&dma_config);
// sbdsp.cur_sample = (int16_t)((dma_data & 0xFF) ^ 0x80) << 8;
#ifdef SB_BUFFERLESS
sbdsp.cur_sample = (int16_t)((dma_data & 0xFF) ^ 0x80) << 8;
#else
sbdsp_fifo_rx(dma_data & 0xFF);
#endif
}
static uint32_t DSP_DAC_Resume_eventHandler(Bitu val) {
@@ -346,9 +347,11 @@ static PIC_TimerEvent DSP_DAC_Resume_event = {
.handler = DSP_DAC_Resume_eventHandler,
};
#ifdef SB_BUFFERLESS
int16_t sbdsp_sample() {
return (sbdsp.speaker_on & ~sbdsp.dac_resume_pending) ? sbdsp.cur_sample : 0;
}
#endif
int16_t sbdsp_muted() {
return (!sbdsp.speaker_on || sbdsp.dac_resume_pending);
@@ -369,7 +372,9 @@ void sbdsp_init() {
sbdsp.outbox = 0xAA;
dma_config = DMA_init(pio0, DMA_PIO_SM, SBDSP_DMA_isr_pt);
#ifndef SB_BUFFERLESS
fifo_init(&sbdsp.audio_fifo);
#endif
}
@@ -402,6 +407,10 @@ void sbdsp_process(void) {
sbdsp_dma_enable();
//printf("(0xD4)DMA RESUME\n\r");
break;
case DSP_EXIT_DMA_8:
sbdsp.autoinit = 0;
sbdsp.current_command = 0;
break;
case DSP_DMA_AUTO:
// printf("(0x1C)DMA_AUTO\n\r");
sbdsp.autoinit=1;
@@ -537,7 +546,9 @@ void sbdsp_process(void) {
case DSP_DIRECT_DAC:
if(sbdsp.dav_dsp) {
if(sbdsp.current_command_index==1) {
#ifdef SB_BUFFERLESS
sbdsp.cur_sample=(int16_t)(sbdsp.inbox) - 0x80 << 5;
#endif
sbdsp.dav_dsp=0;
sbdsp.current_command=0;
}
@@ -625,7 +636,9 @@ static __force_inline void sbdsp_reset(uint8_t value) {
PIC_RemoveEvent(&DSP_Reset_Event);
sbdsp.autoinit=0;
sbdsp_dma_disable();
#ifndef SB_BUFFERLESS
sbdsp_fifo_clear();
#endif
sbdsp.reset_state=1;
break;
case 0:
+21 -37
View File
@@ -34,7 +34,9 @@ extern "C" void OPL_Pico_simple(int16_t *buffer, uint32_t nsamples);
extern "C" void OPL_Pico_PortWrite(opl_port_t, unsigned int);
#ifdef SOUND_SB
#ifdef SB_BUFFERLESS
extern int16_t sbdsp_sample();
#else
// extern uint8_t sbdsp_fifo_tx();
// extern uint16_t sbdsp_fifo_tx(uint8_t *buffer, uint16_t len);
// extern int16_t sbdsp_sample();
@@ -43,7 +45,8 @@ extern int16_t sbdsp_sample();
extern uint16_t sbdsp_sample_rate();
extern uint16_t sbdsp_muted();
extern audio_fifo_t* sbdsp_fifo_peek();
#endif
#endif // SB_BUFFERLESS
#endif // SOUND_SB
#if defined(SOUND_SB) || defined(USB_MOUSE) || defined(SOUND_MPU)
#include "pico_pic.h"
#endif
@@ -165,8 +168,10 @@ void play_adlib() {
struct audio_buffer_pool *ap = init_audio();
#ifndef SB_BUFFERLESS
// uint8_t sb_samples[512] = {128};
audio_fifo_t* sb_fifo = sbdsp_fifo_peek();
#endif
#ifdef CDROM
audio_fifo_t* cd_fifo = cdrom_audio_fifo_peek(&cdrom[0]);
#endif
@@ -179,32 +184,33 @@ void play_adlib() {
uint32_t sb_frac = 0;
// uint32_t sb_sample_idx = 0x0;
uint32_t sb_left = 0;
#ifndef SB_BUFFERLESS
uint32_t sb_state = FIFO_STATE_STOPPED;
#endif
uint32_t cd_left = 0;
uint32_t cd_index = 0;
/*
int16_t opl_samples[512] = {0};
uint32_t opl_ratio = fixed_ratio(49716, 44100);
printf("opl_ratio: %x ", opl_ratio);
uint32_t opl_pos = 0;
uint32_t opl_index = 0;
uint32_t opl_sample_idx = 0x0;
*/
// int16_t cd_samples[1024] = {0};
bool opl_hi = false, opl_lo = false;
int32_t accum[2] = {0};
for (;;) {
// cdrom_audio_callback(&cdrom[0], cd_samples, 1024);
struct audio_buffer *buffer = take_audio_buffer(ap, true);
int16_t *samples = (int16_t *) buffer->buffer->bytes;
// Do mixing with lerp
int32_t accum[2] = {0};
#ifndef SB_BUFFERLESS
for (int i = 0; i < SAMPLES_PER_BUFFER; ++i) {
#endif
accum[0] = accum[1] = 0;
#ifdef CDROM
if (!cd_left) {
@@ -212,6 +218,8 @@ void play_adlib() {
if (cdrom_audio_callback(&cdrom[0], AUDIO_FIFO_SIZE) && fifo_take_samples(cd_fifo, AUDIO_FIFO_SIZE)) {
cd_left = AUDIO_FIFO_SIZE;
// putchar('c');
} else {
// putchar('f');
}
}
if (cd_left) {
@@ -223,7 +231,6 @@ void play_adlib() {
cd_left -= 2;
}
#endif
/*
uint32_t opl_index = (opl_pos >> FRAC_BITS);
// uint32_t opl_index = i;
uint32_t opl_frac = opl_pos & FRAC_MASK;
@@ -236,6 +243,7 @@ void play_adlib() {
(!(opl_index & 0x100) && opl_sample_idx != 0x100)
) {
opl_sample_idx = (opl_index + 0x100) & 0x100;
/*
bool notfirst = false;
while (opl_buffer.tail != opl_buffer.head) {
if (!notfirst) {
@@ -248,6 +256,7 @@ void play_adlib() {
OPL_Pico_PortWrite((opl_port_t)cmd.addr, cmd.data);
++opl_buffer.tail;
}
*/
OPL_Pico_simple(opl_samples + opl_sample_idx, 256);
}
int32_t opl_sample = lerp_fixed(
@@ -256,20 +265,7 @@ void play_adlib() {
opl_frac);
accum[0] += opl_samples[opl_index & 0x1ff];
accum[1] += opl_samples[opl_index & 0x1ff];
*/
/*
if (
sbdsp_fifo_level() >= 128 && (
((sb_index & 0x80) && sb_sample_idx != 0x0) ||
(!(sb_index & 0x80) && sb_sample_idx != 0x80)
)) {
sb_ratio = fixed_ratio(sbdsp_sample_rate(), 44100);
sb_sample_idx = (sb_index + 0x80) & 0x80;
sbdsp_fifo_tx(sb_samples + sb_sample_idx, 128);
}
*/
// int16_t sb_sample;
#ifndef SB_BUFFERLESS
if (!sb_left) {
// putchar('t');
uint32_t tmp_state = fifo_get_state(sb_fifo);
@@ -286,7 +282,7 @@ void play_adlib() {
sb_state = tmp_state;
} else {
if (sb_state == FIFO_STATE_RUNNING) {
putchar('U');
// putchar('U');
}
// printf("%u\n", sb_fifo->samples_in_fifo);
}
@@ -295,10 +291,6 @@ void play_adlib() {
sb_index = (sb_pos >> FRAC_BITS);
int16_t sb_sample;
if (sb_index_old != sb_index) {
// fifo_take_samples(sb_fifo, 1);
// if (fifo_take_samples(sb_fifo, 1)) {
// }
sb_left--;
}
sb_index_old = sb_index;
@@ -314,23 +306,15 @@ void play_adlib() {
accum[1] += sb_sample;
}
}
samples[i << 1] = clamp16(accum[0]);
samples[(i << 1) + 1] = clamp16(accum[1]);
}
/*
// bufferless SB
int16_t sb_sample = sbdsp_sample();
accum[0] += sb_sample;
accum[1] += sb_sample;
buffer->sample_count = SAMPLES_PER_BUFFER;
#else // ifndef SB_BUFFERLESS
samples[0] = clamp16(accum[0]);
samples[1] = clamp16(accum[1]);
buffer->sample_count = 1;
*/
buffer->sample_count = SAMPLES_PER_BUFFER;
#endif // ifndef SB_BUFFERLESS
give_audio_buffer(ap, buffer);
#ifdef USB_STACK
// Service TinyUSB events