Skip to content

Commit

Permalink
machine/t10mmc: Implement T10MMC_CMD_SCAN
Browse files Browse the repository at this point in the history
  • Loading branch information
987123879113 committed Mar 30, 2024
1 parent 62d1577 commit 507344b
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 2 deletions.
48 changes: 47 additions & 1 deletion src/devices/machine/t10mmc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -571,6 +571,51 @@ void t10mmc::ExecCommand()
m_transfer_length = m_blocks * m_sector_bytes;
break;

case T10MMC_CMD_SCAN:
{
const int direction = BIT(command[1], 4); // 0 = forward, 1 = reverse
const uint32_t start_addr = get_u32be(&command[2]);
const int scan_type = BIT(command[9], 6, 2); // 0 = lba, 1 = msf, 2 = track num, 3 = reserved

m_device->logerror("T10MMC: SCAN direction %d type %d addr %06x\n", direction, scan_type, start_addr);

uint32_t lba = 0;
switch (scan_type)
{
case 0: // lba
lba = start_addr;
break;
case 1: // msf
lba = to_lba(start_addr & 0xffffff);
break;
case 2: // track number
lba = m_image->get_track_start(start_addr & 0xff);
break;
default:
m_device->logerror("T10MMC: unsupported scan type! %d\n", scan_type);
break;
}

const int trk = m_image->get_track(m_lba);
if (m_image->get_track_type(trk) != cdrom_file::CD_TRACK_AUDIO)
{
m_device->logerror("T10MMC: scan target track is NOT audio!\n");
set_sense(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_SENSE_ASC_ASCQ_ILLEGAL_MODE_FOR_THIS_TRACK);
m_status_code = SCSI_STATUS_CODE_CHECK_CONDITION;
}
else
{
const uint32_t disc_end_lba = m_image->get_track_start(m_image->get_last_track());
m_cdda->start_audio(lba, disc_end_lba - lba);
m_cdda->set_audio_scan(direction ? -150 : 190); // recommended values in t10 docs for forward and reverse

m_audio_sense = SCSI_SENSE_ASC_ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS;
m_status_code = SCSI_STATUS_CODE_GOOD;
}

break;
}

case T10MMC_CMD_SET_CD_SPEED:
m_device->logerror("T10MMC: SET CD SPEED to %d kbytes/sec.\n", get_u16be(&command[2]));
m_phase = SCSI_PHASE_STATUS;
Expand Down Expand Up @@ -1172,7 +1217,8 @@ void t10mmc::ReadData( uint8_t *data, int dataLength )
data[0]= 0x00;

const int audio_active = m_cdda->audio_active();
if (audio_active)
const int audio_is_scanning = m_cdda->is_scanning();
if (audio_active || audio_is_scanning)
{
// if audio is playing, get the latest LBA from the CDROM layer
m_last_lba = m_cdda->get_audio_lba();
Expand Down
64 changes: 63 additions & 1 deletion src/devices/sound/cdda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ void cdda_device::device_start()
m_audio_length = 0;
m_audio_samples = 0;
m_audio_bptr = 0;
m_audio_scan_offset = 0;
m_audio_scan_next_lba = 0;
m_audio_scan_play_length = 0;
m_sequence_counter = 0;

save_item( NAME(m_audio_playing) );
Expand All @@ -49,7 +52,9 @@ void cdda_device::device_start()
save_item( NAME(m_audio_samples) );
save_item( NAME(m_audio_bptr) );
save_item( NAME(m_sequence_counter) );

save_item( NAME(m_audio_scan_offset) );
save_item( NAME(m_audio_scan_play_length) );
save_item( NAME(m_audio_scan_next_lba) );
}


Expand All @@ -67,6 +72,8 @@ void cdda_device::start_audio(uint32_t startlba, uint32_t numblocks)
m_audio_lba = startlba;
m_audio_length = numblocks;
m_audio_samples = 0;

stop_audio_scan();
}


Expand All @@ -80,6 +87,8 @@ void cdda_device::stop_audio()
m_stream->update();
m_audio_playing = false;
m_audio_ended_normally = true;

stop_audio_scan();
}


Expand All @@ -92,6 +101,8 @@ void cdda_device::pause_audio(int pause)
{
m_stream->update();
m_audio_pause = pause;

stop_audio_scan();
}


Expand Down Expand Up @@ -142,6 +153,40 @@ int cdda_device::audio_ended()
}


/*-------------------------------------------------
set_audio_scan - enable scanning mode.
the offset can be negative for reverse
scanning or positive for forward scanning,
or 0 to disable scanning. the optional play
length value controls how many frames of audio
to play between each scan.
t10 spec recommendations:
forward scan offset = 190
reverse scan offset = -150
play length = 6
-------------------------------------------------*/

void cdda_device::set_audio_scan(int32_t offset, uint32_t play_length)
{
m_audio_scan_offset = offset;
m_audio_length = m_audio_scan_play_length = play_length;
m_audio_scan_next_lba = m_audio_lba + play_length;
}


/*-------------------------------------------------
stop_audio_scan - stop and reset scan parameters
-------------------------------------------------*/

void cdda_device::stop_audio_scan()
{
m_audio_scan_offset = 0;
m_audio_scan_play_length = 0;
m_audio_scan_next_lba = 0;
}


/*-------------------------------------------------
get_audio_data - reads Red Book data off
the disc if playback is in progress and
Expand All @@ -153,6 +198,23 @@ void cdda_device::get_audio_data(write_stream_view &bufL, write_stream_view &buf
int i;
int16_t *audio_cache = (int16_t *) m_audio_cache.get();

if (m_audio_scan_offset != 0 && m_audio_lba >= m_audio_scan_next_lba)
{
const uint32_t end_lba = m_disc->get_track_start(m_disc->get_last_track());

m_audio_lba = std::min(std::max(0, int32_t(m_audio_lba) + m_audio_scan_offset), int32_t(end_lba));
m_audio_length = m_audio_scan_play_length;
m_audio_scan_next_lba = m_audio_lba + m_audio_scan_play_length;
m_audio_samples = 0;

const int track_type = m_disc->get_track_type(m_disc->get_track(m_audio_lba));
if (m_audio_lba == 0 || m_audio_lba >= end_lba || track_type != cdrom_file::CD_TRACK_AUDIO)
{
// stop if very start, very end, or non-audio track is reached
m_audio_length = m_audio_samples = m_audio_scan_offset = 0;
}
}

for (int sampindex = 0; sampindex < bufL.samples(); )
{
/* if no file, audio not playing, audio paused, or out of disc data,
Expand Down
8 changes: 8 additions & 0 deletions src/devices/sound/cdda.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@ class cdda_device : public device_t, public device_sound_interface
void start_audio(uint32_t startlba, uint32_t numblocks);
void stop_audio();
void pause_audio(int pause);
void set_audio_scan(int32_t offset, uint32_t play_length = 6);
void stop_audio_scan();
int16_t get_channel_sample(int channel);

uint32_t get_audio_lba();
int is_scanning() { return m_audio_scan_offset != 0; }

int audio_active();
int audio_paused();
int audio_ended();
Expand Down Expand Up @@ -52,6 +56,10 @@ class cdda_device : public device_t, public device_sound_interface

uint32_t m_sequence_counter;

int32_t m_audio_scan_offset;
uint32_t m_audio_scan_play_length;
uint32_t m_audio_scan_next_lba;

devcb_write_line m_audio_end_cb;
};

Expand Down

0 comments on commit 507344b

Please sign in to comment.