Fix PCM playback in ZSM backend
This commit is contained in:
parent
28314c4372
commit
b52a316511
4 changed files with 71 additions and 38 deletions
|
@ -180,14 +180,21 @@ pcm_render(int16_t *buf, unsigned num_samples)
|
||||||
*(buf++) = (int16_t)((int32_t)cur_r * volume_lut[ctrl & 0xF] / 64);
|
*(buf++) = (int16_t)((int32_t)cur_r * volume_lut[ctrl & 0xF] / 64);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint32_t pcm_fifo_avail(void) {
|
uint32_t pcm_fifo_cnt(void) {
|
||||||
uint32_t cnt_adj = fifo_cnt;
|
return fifo_cnt;
|
||||||
|
}
|
||||||
|
uint32_t pcm_sample_size(void) {
|
||||||
|
uint32_t output = 1;
|
||||||
switch ((ctrl >> 4) & 3) {
|
switch ((ctrl >> 4) & 3) {
|
||||||
case 3: cnt_adj /= 2;
|
case 3: output *= 2;
|
||||||
case 2:
|
case 2:
|
||||||
case 1: cnt_adj /= 2;
|
case 1: output *= 2;
|
||||||
case 0: break;
|
case 0: break;
|
||||||
}
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
uint32_t pcm_fifo_avail(void) {
|
||||||
|
uint32_t cnt_adj = fifo_cnt / pcm_sample_size();
|
||||||
uint32_t output = 0;
|
uint32_t output = 0;
|
||||||
uint32_t _phase = phase;
|
uint32_t _phase = phase;
|
||||||
while (cnt_adj != 0) {
|
while (cnt_adj != 0) {
|
||||||
|
|
|
@ -16,3 +16,5 @@ void pcm_write_fifo(uint8_t val);
|
||||||
void pcm_render(int16_t *buf, unsigned num_samples);
|
void pcm_render(int16_t *buf, unsigned num_samples);
|
||||||
uint32_t pcm_fifo_avail(void);
|
uint32_t pcm_fifo_avail(void);
|
||||||
bool pcm_is_fifo_almost_empty(void);
|
bool pcm_is_fifo_almost_empty(void);
|
||||||
|
uint32_t pcm_fifo_cnt(void);
|
||||||
|
uint32_t pcm_sample_size(void);
|
||||||
|
|
|
@ -47,6 +47,37 @@ void ZsmBackend::load(const char *filename) {
|
||||||
file->read(loop_point, 1, 1);
|
file->read(loop_point, 1, 1);
|
||||||
pcm_offset++;
|
pcm_offset++;
|
||||||
pcm_data_offs = ((((uint16_t)loop_point[0]) + 1) * 16) + pcm_offset;
|
pcm_data_offs = ((((uint16_t)loop_point[0]) + 1) * 16) + pcm_offset;
|
||||||
|
for (uint8_t i = 0; i <= loop_point[0]; i++) {
|
||||||
|
uint16_t instdef = (i * 16) + 1;
|
||||||
|
pcm_instrument *inst = new pcm_instrument();
|
||||||
|
file->seek(pcm_offset + instdef, SeekType::SET);
|
||||||
|
file->read(&inst->geom, 1, 1);
|
||||||
|
uint8_t bytes[10];
|
||||||
|
file->read(bytes, 10, 1);
|
||||||
|
inst->loop_rem = bytes[9];
|
||||||
|
inst->loop_rem <<= 8;
|
||||||
|
inst->loop_rem |= bytes[8];
|
||||||
|
inst->loop_rem <<= 8;
|
||||||
|
inst->loop_rem |= bytes[7];
|
||||||
|
inst->loop = loop_rem;
|
||||||
|
inst->islooped = bytes[6] & 0x80;
|
||||||
|
inst->remain = bytes[5];
|
||||||
|
inst->remain <<= 8;
|
||||||
|
inst->remain |= bytes[4];
|
||||||
|
inst->remain <<= 8;
|
||||||
|
inst->remain |= bytes[3];
|
||||||
|
uint32_t cur = bytes[2];
|
||||||
|
cur <<= 8;
|
||||||
|
cur |= bytes[1];
|
||||||
|
cur <<= 8;
|
||||||
|
cur |= bytes[0];
|
||||||
|
cur += pcm_data_offs;
|
||||||
|
inst->data = (uint8_t*)malloc(inst->remain);
|
||||||
|
file->seek(cur, SeekType::SET);
|
||||||
|
file->read(inst->data, 1, inst->remain);
|
||||||
|
inst->loop_rem = inst->remain - inst->loop_rem;
|
||||||
|
instruments.push_back(inst);
|
||||||
|
}
|
||||||
file->seek(music_data_start, SeekType::SET);
|
file->seek(music_data_start, SeekType::SET);
|
||||||
this->loop_point = std::max(this->loop_point, (uint32_t)music_data_start);
|
this->loop_point = std::max(this->loop_point, (uint32_t)music_data_start);
|
||||||
double prev_time = 0.0;
|
double prev_time = 0.0;
|
||||||
|
@ -106,6 +137,11 @@ void ZsmBackend::cleanup() {
|
||||||
audio_buf.clear();
|
audio_buf.clear();
|
||||||
SDL_FreeAudioStream(fm_stream);
|
SDL_FreeAudioStream(fm_stream);
|
||||||
fm_stream = nullptr;
|
fm_stream = nullptr;
|
||||||
|
audio_sample = nullptr;
|
||||||
|
for (auto inst : instruments) {
|
||||||
|
delete inst;
|
||||||
|
}
|
||||||
|
instruments.clear();
|
||||||
}
|
}
|
||||||
void ZsmBackend::tick(bool step) {
|
void ZsmBackend::tick(bool step) {
|
||||||
delayTicks -= 1;
|
delayTicks -= 1;
|
||||||
|
@ -167,40 +203,18 @@ void ZsmBackend::tick(bool step) {
|
||||||
uint8_t ctrl = pcm_read_ctrl();
|
uint8_t ctrl = pcm_read_ctrl();
|
||||||
pcm_write_ctrl(ctrl | 0x80);
|
pcm_write_ctrl(ctrl | 0x80);
|
||||||
uint16_t pcm_idx = cmd.extcmd.pcm[i + 1];
|
uint16_t pcm_idx = cmd.extcmd.pcm[i + 1];
|
||||||
uint16_t instdef = pcm_idx * 16;
|
pcm_instrument *inst = instruments[pcm_idx];
|
||||||
file->seek(pcm_offset + instdef, SeekType::SET);
|
|
||||||
uint8_t geom;
|
|
||||||
file->read(&geom, 1, 1);
|
|
||||||
ctrl = pcm_read_ctrl() & 0x0F;
|
ctrl = pcm_read_ctrl() & 0x0F;
|
||||||
ctrl |= geom & 0x30;
|
ctrl |= inst->geom & 0x30;
|
||||||
pcm_write_ctrl(ctrl);
|
pcm_write_ctrl(ctrl);
|
||||||
uint8_t bytes[10];
|
audio_sample = inst->data;
|
||||||
file->read(bytes, 10, 1);
|
loop = inst->loop;
|
||||||
loop_rem = bytes[9];
|
loop_rem = inst->loop_rem;
|
||||||
loop_rem <<= 8;
|
remain = inst->remain;
|
||||||
loop_rem |= bytes[8];
|
islooped = inst->islooped;
|
||||||
loop_rem <<= 8;
|
cur = 0;
|
||||||
loop_rem |= bytes[7];
|
|
||||||
loop = loop_rem;
|
|
||||||
islooped = bytes[6] & 0x80;
|
|
||||||
remain = bytes[5];
|
|
||||||
remain <<= 8;
|
|
||||||
remain |= bytes[4];
|
|
||||||
remain <<= 8;
|
|
||||||
remain |= bytes[3];
|
|
||||||
cur = bytes[2];
|
|
||||||
cur <<= 8;
|
|
||||||
cur |= bytes[1];
|
|
||||||
cur <<= 8;
|
|
||||||
cur |= bytes[0];
|
|
||||||
cur += pcm_data_offs;
|
|
||||||
loop += cur;
|
|
||||||
loop_rem = remain - loop_rem;
|
|
||||||
file->seek(file_pos, SeekType::SET);
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
//cmd.extcmd.pcm
|
|
||||||
audio_step(0);
|
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
// Nothing handled yet.
|
// Nothing handled yet.
|
||||||
|
|
|
@ -60,6 +60,17 @@ struct ZsmCommand {
|
||||||
};
|
};
|
||||||
~ZsmCommand();
|
~ZsmCommand();
|
||||||
};
|
};
|
||||||
|
struct pcm_instrument {
|
||||||
|
uint8_t geom;
|
||||||
|
uint32_t loop_rem;
|
||||||
|
uint32_t loop;
|
||||||
|
bool islooped;
|
||||||
|
uint32_t remain;
|
||||||
|
uint8_t *data = nullptr;
|
||||||
|
inline ~pcm_instrument() {
|
||||||
|
if (data != nullptr) free((void*)data);
|
||||||
|
}
|
||||||
|
};
|
||||||
class ZsmBackend : public PlaybackBackend {
|
class ZsmBackend : public PlaybackBackend {
|
||||||
File *file;
|
File *file;
|
||||||
Fifo<int16_t> audio_buf;
|
Fifo<int16_t> audio_buf;
|
||||||
|
@ -80,6 +91,8 @@ class ZsmBackend : public PlaybackBackend {
|
||||||
uint32_t pcm_loop_point;
|
uint32_t pcm_loop_point;
|
||||||
uint32_t rem_point;
|
uint32_t rem_point;
|
||||||
SDL_AudioStream *fm_stream;
|
SDL_AudioStream *fm_stream;
|
||||||
|
std::vector<pcm_instrument*> instruments;
|
||||||
|
uint8_t *audio_sample = nullptr;
|
||||||
int16_t combine_audio(int16_t a, int16_t b) {
|
int16_t combine_audio(int16_t a, int16_t b) {
|
||||||
return (int16_t)((((int32_t)a) + ((int32_t)b)) >> 1);
|
return (int16_t)((((int32_t)a) + ((int32_t)b)) >> 1);
|
||||||
}
|
}
|
||||||
|
@ -96,11 +109,8 @@ class ZsmBackend : public PlaybackBackend {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size_t oldpos = file->get_pos();
|
size_t oldpos = file->get_pos();
|
||||||
file->seek((cur++), SeekType::SET);
|
uint8_t sample = audio_sample[cur++];
|
||||||
uint8_t sample;
|
|
||||||
file->read(&sample, 1, 1);
|
|
||||||
pcm_write_fifo(sample);
|
pcm_write_fifo(sample);
|
||||||
file->seek(oldpos, SeekType::SET);
|
|
||||||
}
|
}
|
||||||
samples *= 2;
|
samples *= 2;
|
||||||
int16_t *psg_ptr = psg_buf.get_item_sized<int16_t>(samples);
|
int16_t *psg_ptr = psg_buf.get_item_sized<int16_t>(samples);
|
||||||
|
|
Loading…
Reference in a new issue