-
Notifications
You must be signed in to change notification settings - Fork 2.2k
CD-i: Add Audio Mixing #14481
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
base: master
Are you sure you want to change the base?
CD-i: Add Audio Mixing #14481
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -318,50 +318,33 @@ void cdicdic_device::play_raw_group(const uint8_t *data) | |
| m_dmadac[1]->transfer(0, 1, 1, 28, samples); | ||
| } | ||
|
|
||
| void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data) | ||
| void cdicdic_device::play_xa_group(const uint8_t coding, const uint8_t *data, const uint16_t idx) | ||
| { | ||
| static const uint16_t s_4bit_header_offsets[8] = { 4, 5, 6, 7, 12, 13, 14, 15 }; | ||
| static const uint16_t s_8bit_header_offsets[4] = { 4, 5, 6, 7 }; | ||
| static const uint16_t s_4bit_data_offsets[8] = { 16, 16, 17, 17, 18, 18, 19, 19 }; | ||
| static const uint16_t s_8bit_data_offsets[4] = { 16, 17, 18, 19 }; | ||
|
|
||
| int16_t samples[28]; | ||
|
|
||
| switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) | ||
| uint8_t num_samples = coding&CODING_8BPS ? 4 : 8; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing spaces. |
||
| for (uint8_t i = 0; i < num_samples; i++) | ||
| { | ||
| switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) | ||
| { | ||
| case CODING_4BPS | CODING_MONO: | ||
| for (uint8_t i = 0; i < 8; i++) | ||
| { | ||
| decode_4bit_xa_unit(0, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); | ||
| m_dmadac[0]->transfer(0, 1, 1, 28, samples); | ||
| m_dmadac[1]->transfer(0, 1, 1, 28, samples); | ||
| } | ||
| return; | ||
| decode_4bit_xa_unit(0, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, &m_samples[0][idx + i * 28]); | ||
| break; | ||
|
|
||
| case CODING_4BPS | CODING_STEREO: | ||
| for (uint8_t i = 0; i < 8; i++) | ||
| { | ||
| decode_4bit_xa_unit(i & 1, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, samples); | ||
| m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); | ||
| } | ||
| return; | ||
| decode_4bit_xa_unit(i & 1, data[s_4bit_header_offsets[i]], data + s_4bit_data_offsets[i], (i & 1) ? 4 : 0, &m_samples[i & 1][idx + (i >> 1) * 28]); | ||
| break; | ||
|
|
||
| case CODING_8BPS | CODING_MONO: | ||
| for (uint8_t i = 0; i < 4; i++) | ||
| { | ||
| decode_8bit_xa_unit(0, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); | ||
| m_dmadac[0]->transfer(0, 1, 1, 28, samples); | ||
| m_dmadac[1]->transfer(0, 1, 1, 28, samples); | ||
| } | ||
| return; | ||
| decode_8bit_xa_unit(0, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], &m_samples[0][idx + i * 28]); | ||
| break; | ||
|
|
||
| case CODING_8BPS | CODING_STEREO: | ||
| for (uint8_t i = 0; i < 4; i++) | ||
| { | ||
| decode_8bit_xa_unit(i & 1, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], samples); | ||
| m_dmadac[i & 1]->transfer(0, 1, 1, 28, samples); | ||
| } | ||
| return; | ||
| decode_8bit_xa_unit(i & 1, data[s_8bit_header_offsets[i]], data + s_8bit_data_offsets[i], &m_samples[i & 1][idx + (i >> 1) * 28]); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -377,10 +360,12 @@ void cdicdic_device::play_cdda_sector(const uint8_t *data) | |
| { | ||
| samples[0][i] = (int16_t)((data[(i * 4) + 1] << 8) | data[(i * 4) + 0]); | ||
| samples[1][i] = (int16_t)((data[(i * 4) + 3] << 8) | data[(i * 4) + 2]); | ||
| m_samples[0][i] = samples[0][i]; | ||
| m_samples[1][i] = samples[1][i]; | ||
| } | ||
|
|
||
| m_dmadac[0]->transfer(0, 1, 1, SECTOR_SIZE/4, samples[0]); | ||
| m_dmadac[1]->transfer(0, 1, 1, SECTOR_SIZE/4, samples[1]); | ||
| m_dmadac[0]->transfer(0, 1, 1, SECTOR_SIZE/4, &m_samples[0][0]); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More missing spaces. If the line is being changed anyway, might as well fix the spacing along the way. The whole file could use a sweep for operator-spacing normalization. |
||
| m_dmadac[1]->transfer(0, 1, 1, SECTOR_SIZE/4, &m_samples[1][0]); | ||
| } | ||
|
|
||
| void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data) | ||
|
|
@@ -439,6 +424,19 @@ void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data | |
| m_dmadac[0]->set_volume(0x100); | ||
| m_dmadac[1]->set_volume(0x100); | ||
|
|
||
| uint8_t num_samples = 4; | ||
|
|
||
| switch (coding & (CODING_BPS_MASK | CODING_CHAN_MASK)) | ||
| { | ||
| case CODING_4BPS | CODING_MONO: | ||
| num_samples = 8; | ||
| break; | ||
| case CODING_8BPS | CODING_STEREO: | ||
| num_samples = 2; | ||
| break; | ||
| } | ||
|
|
||
|
|
||
| if (bits == 16 && channels == 2) | ||
| { | ||
| for (uint16_t i = 0; i < SECTOR_AUDIO_SIZE; i += 112, data += 112) | ||
|
|
@@ -448,13 +446,36 @@ void cdicdic_device::play_audio_sector(const uint8_t coding, const uint8_t *data | |
| } | ||
| else | ||
| { | ||
| uint16_t offset = 0; | ||
| for (uint16_t i = 0; i < SECTOR_AUDIO_SIZE; i += 128, data += 128) | ||
| { | ||
| play_xa_group(coding, data); | ||
| play_xa_group(coding, data, offset); | ||
| offset += 28 * num_samples; | ||
| } | ||
| int16_t sampleL = 0, sampleR = 0, outL = 0, outR = 0; | ||
| for (uint16_t i = 0; i < 18 * 28 * num_samples; i++) { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. File uses Allman style. |
||
| sampleL = m_samples[0][i]; | ||
| sampleR = m_samples[coding & CODING_STEREO][i]; | ||
|
|
||
| float scaleLL = powf(10.0f, -m_atten[0] / 20.0f); | ||
| float scaleLR = powf(10.0f, -m_atten[1] / 20.0f); | ||
| float scaleRR = powf(10.0f, -m_atten[2] / 20.0f); | ||
| float scaleRL = powf(10.0f, -m_atten[3] / 20.0f); | ||
| outL = (sampleL * scaleLL + sampleR * scaleRL) * 0.5; | ||
| outR = (sampleL * scaleLR + sampleR * scaleRR) * 0.5; | ||
| m_dmadac[0]->transfer(0, 1, 1, 1, &outL); | ||
| m_dmadac[1]->transfer(0, 1, 1, 1, &outR); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| void cdicdic_device::atten_w(uint8_t* args) { | ||
| m_atten[0] = ((args[0] & 0x8) << 7) | args[1]; | ||
| m_atten[1] = ((args[0] & 0x4) << 7) | args[2]; | ||
| m_atten[2] = ((args[0] & 0x2) << 7) | args[3]; | ||
| m_atten[3] = ((args[0] & 0x1) << 7) | args[4]; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Following on from Kale's comment, it's pretty unlikely that the real hardware connection between the SLAVE and CDIC devices is 20 individual traces for the 20 bits of state represented by The correct way to do this would be to have
rather than grabbing into a protected class member in a way that doesn't compile.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a temporary fix to expose the cdic for dynamic casting just so that it compiles so it can be validated it worked. Thanks for the feedback, I'll look into the callback change. |
||
| } | ||
|
|
||
| TIMER_CALLBACK_MEMBER( cdicdic_device::audio_tick ) | ||
| { | ||
| if (m_audio_sector_counter > 0) | ||
|
|
@@ -1318,6 +1339,7 @@ void cdicdic_device::device_start() | |
| save_item(NAME(m_decode_addr)); | ||
|
|
||
| save_item(NAME(m_xa_last)); | ||
| save_item(NAME(m_atten)); | ||
|
|
||
| m_audio_timer = timer_alloc(FUNC(cdicdic_device::audio_tick), this); | ||
| m_audio_timer->adjust(attotime::never); | ||
|
|
@@ -1364,7 +1386,8 @@ void cdicdic_device::device_reset() | |
| m_dmadac[0]->enable(1); | ||
| m_dmadac[1]->enable(1); | ||
|
|
||
| std::fill_n(&m_xa_last[0], 4, 0); | ||
| std::fill_n(m_xa_last, 4, 0); | ||
| std::fill_n(m_atten, 4, 0); | ||
| } | ||
|
|
||
| void cdicdic_device::ram_w(offs_t offset, uint16_t data, uint16_t mem_mask) | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,6 +29,7 @@ | |
|
|
||
| #define VERBOSE (0) | ||
| #include "logmacro.h" | ||
| #include "cdi.h" | ||
|
|
||
| // device type definition | ||
| DEFINE_DEVICE_TYPE(CDI_SLAVE_HLE, cdislave_hle_device, "cdislavehle", "CD-i Mono-I Slave HLE") | ||
|
|
@@ -227,6 +228,12 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) | |
| { | ||
| switch (m_in_buf[0]) | ||
| { | ||
| case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: | ||
| case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: | ||
| dynamic_cast<cdi_state*>(m_owner)->m_cdic->atten_w(m_in_buf); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is unportable, you should rather provide this communication thru |
||
| m_in_index = 0; | ||
| m_in_count = 0; | ||
| break; | ||
| case 0xf0: // Set Front Panel LCD | ||
| memset(m_in_buf + 1, 0, 16); | ||
| m_in_count = 17; | ||
|
|
@@ -264,6 +271,13 @@ void cdislave_hle_device::slave_w(offs_t offset, uint16_t data) | |
| m_in_count = 0; | ||
| break; | ||
| } | ||
| case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc4: case 0xc5: case 0xc6: case 0xc7: | ||
| case 0xc8: case 0xc9: case 0xca: case 0xcb: case 0xcc: case 0xcd: case 0xce: case 0xcf: | ||
| { | ||
| LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Set Attenuation Audio\n", offset); | ||
| m_in_count = 5; | ||
| break; | ||
| } | ||
| case 0xf0: // Set Front Panel LCD | ||
| LOGMASKED(LOG_COMMANDS, "slave_w: Channel %d: Set Front Panel LCD (0xf0)\n", offset); | ||
| m_in_count = 17; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unsure if I originally added these or someone else did, but the s_ prefix is unnecessary, and
SHOUTY_CAPSis prefered for constants; something likeHEADER_OFFSETS_4BITet al would be nicer.