Skip to content

Commit f82a291

Browse files
committed
[sgu] Generate 48kHz sample, resample to sokol samplerate later
1 parent 20b8480 commit f82a291

File tree

4 files changed

+15
-28
lines changed

4 files changed

+15
-28
lines changed

src/chips/sgu1.c

Lines changed: 4 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -21,41 +21,34 @@
2121
void sgu1_init(sgu1_t* sgu, const sgu1_desc_t* desc) {
2222
CHIPS_ASSERT(sgu && desc);
2323
CHIPS_ASSERT(desc->tick_hz > 0);
24-
CHIPS_ASSERT(desc->sound_hz > 0);
2524
memset(sgu, 0, sizeof(*sgu));
26-
sgu->sound_hz = desc->sound_hz;
27-
sgu->sample_period = (desc->tick_hz * SGU1_FIXEDPOINT_SCALE) / desc->sound_hz;
28-
sgu->sample_counter = sgu->sample_period;
2925
sgu->sample_mag = desc->magnitude;
3026
sgu->tick_period = (desc->tick_hz * SGU1_FIXEDPOINT_SCALE) / SGU1_CHIP_CLOCK;
3127
sgu->tick_counter = sgu->tick_period;
3228
SoundUnit_Init(&sgu->su, 65536);
33-
sgu->resampler = speex_resampler_init(SGU1_AUDIO_CHANNELS, SGU1_CHIP_CLOCK, sgu->sound_hz, 10, nullptr);
3429
}
3530

3631
void sgu1_reset(sgu1_t* sgu) {
3732
CHIPS_ASSERT(sgu);
3833
SoundUnit_Reset(&sgu->su);
3934
memset(sgu->reg, 0, sizeof(sgu->reg));
4035
sgu->tick_counter = sgu->tick_period;
41-
sgu->sample_counter = sgu->sample_period;
4236
sgu->sample[0] = sgu->sample[1] = 0.0f;
4337
sgu->pins = 0;
44-
speex_resampler_reset_mem(sgu->resampler);
4538
}
4639

4740
/* tick the sound generation, return true when new sample ready */
4841
static uint64_t _sgu1_tick(sgu1_t* sgu, uint64_t pins) {
42+
pins &= ~SGU1_SAMPLE;
4943
/* next sample? */
5044
sgu->tick_counter -= SGU1_FIXEDPOINT_SCALE;
5145
while (sgu->tick_counter <= 0) {
5246
sgu->tick_counter += sgu->tick_period;
5347
int32_t l, r;
5448
SoundUnit_NextSample(&sgu->su, &l, &r);
55-
float in[2] = { ((float)l / 32767.0f), ((float)r / 32767.0f) };
56-
spx_uint32_t in_len = 1; // 1 stereo frame
57-
spx_uint32_t out_len = 1; // room for 1 stereo frame
58-
speex_resampler_process_interleaved_float(sgu->resampler, in, &in_len, sgu->sample, &out_len);
49+
sgu->sample[0] = sgu->sample_mag * (float)l / 32767.0f;
50+
sgu->sample[1] = sgu->sample_mag * (float)r / 32767.0f;
51+
pins |= SGU1_SAMPLE;
5952

6053
for (uint8_t i = 0; i < SGU1_NUM_CHANNELS; i++) {
6154
sgu->voice[i].sample_buffer[sgu->voice[i].sample_pos++] = (float)(SoundUnit_GetSample(&sgu->su, i));
@@ -64,16 +57,6 @@ static uint64_t _sgu1_tick(sgu1_t* sgu, uint64_t pins) {
6457
}
6558
}
6659
}
67-
68-
/* new sample? */
69-
pins &= ~SGU1_SAMPLE;
70-
sgu->sample_counter -= SGU1_FIXEDPOINT_SCALE;
71-
while (sgu->sample_counter <= 0) {
72-
sgu->sample_counter += sgu->sample_period;
73-
sgu->sample[0] = sgu->sample_mag * sgu->sample[0];
74-
sgu->sample[1] = sgu->sample_mag * sgu->sample[1];
75-
pins |= SGU1_SAMPLE;
76-
}
7760
return pins;
7861
}
7962

src/chips/sgu1.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,12 +170,11 @@ extern "C" {
170170
#define SGU1_VOL_SWEEP_BOUNCE (1 << 7)
171171

172172
#define SGU1_AUDIO_CHANNELS (2)
173-
#define SGU1_AUDIO_SAMPLES (4096)
173+
#define SGU1_AUDIO_SAMPLES (1024)
174174

175175
// setup parameters for sgu1_init()
176176
typedef struct {
177177
int tick_hz; // frequency at which sgu1_tick() will be called in Hz
178-
int sound_hz; // sound sample frequency
179178
float magnitude; // output sample magnitude (0=silence to 1=max volume)
180179
} sgu1_desc_t;
181180

@@ -187,10 +186,7 @@ typedef struct {
187186
uint8_t reg[32];
188187
int tick_period;
189188
int tick_counter;
190-
SpeexResamplerState* resampler;
191189
// sample generation state
192-
int sample_period;
193-
int sample_counter;
194190
float sample_mag;
195191
float sample[SGU1_AUDIO_CHANNELS]; // Left, Right
196192
// voice visualization

src/systems/x65.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,6 @@ void x65_init(x65_t* sys, const x65_desc_t* desc) {
6464
&sys->sgu,
6565
&(sgu1_desc_t){
6666
.tick_hz = X65_FREQUENCY,
67-
.sound_hz = _X65_DEFAULT(desc->audio.sample_rate, 44100),
6867
.magnitude = _X65_DEFAULT(desc->audio.volume, 1.0f),
6968
});
7069
beeper_init(

src/x65.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ static struct {
6868
} dbg;
6969
x65_snapshot_t snapshots[UI_SNAPSHOT_MAX_SLOTS];
7070
#endif
71+
SpeexResamplerState* resampler;
7172
} state;
7273

7374
#ifdef CHIPS_USE_UI
@@ -110,7 +111,11 @@ static void* labels = NULL;
110111
// audio-streaming callback
111112
static void push_audio(const float* samples, int num_samples, void* user_data) {
112113
(void)user_data;
113-
saudio_push(samples, num_samples / X65_AUDIO_CHANNELS);
114+
spx_uint32_t in_len = num_samples / X65_AUDIO_CHANNELS;
115+
spx_uint32_t out_len = X65_MAX_AUDIO_SAMPLES;
116+
static float buf[X65_MAX_AUDIO_SAMPLES];
117+
speex_resampler_process_interleaved_float(state.resampler, samples, &in_len, buf, &out_len);
118+
saudio_push(buf, out_len);
114119
}
115120

116121
// get x65_desc_t struct based on joystick type
@@ -146,12 +151,15 @@ static void app_load_rom_labels(const char* rom_file) {
146151
}
147152
#endif
148153
}
154+
#define SGU_CHIP_CLOCK (48000)
149155

150156
void app_init(void) {
151157
saudio_setup(&(saudio_desc){
158+
.sample_rate = SGU_CHIP_CLOCK,
152159
.num_channels = X65_AUDIO_CHANNELS,
153160
.logger.func = slog_func,
154161
});
162+
state.resampler = speex_resampler_init(SGU1_AUDIO_CHANNELS, SGU_CHIP_CLOCK, saudio_sample_rate(), 4, 0);
155163
x65_joystick_type_t joy_type = arguments.joy ? X65_JOYSTICKTYPE_DIGITAL_1 : X65_JOYSTICKTYPE_NONE;
156164
if (sargs_exists("joystick")) {
157165
if (sargs_equals("joystick", "digital_1")) {
@@ -354,6 +362,7 @@ void app_cleanup(void) {
354362
ui_discard();
355363
#endif
356364
saudio_shutdown();
365+
speex_resampler_destroy(state.resampler);
357366
gfx_shutdown();
358367
sargs_shutdown();
359368
hid_shutdown();

0 commit comments

Comments
 (0)