static int getsub_deinterleaved (uae_u8 *dst, struct cdunit *cdu, struct cdtoc *t, int sector) { int ret = 0; uae_sem_wait (&cdu->sub_sem); if (t->subcode) { if (t->enctype == ENC_CHD) { const cdrom_track_info *cti = t->chdtrack; ret = do_read (cdu, t, dst, sector, cti->datasize, cti->subsize); if (ret) ret = t->subcode; } else if (t->subhandle) { int offset = 0; int totalsize = SUB_CHANNEL_SIZE; if (t->skipsize) { totalsize += t->size; offset = t->size; } zfile_fseek (t->subhandle, (uae_u64)sector * totalsize + t->suboffset + offset, SEEK_SET); if (zfile_fread (dst, SUB_CHANNEL_SIZE, 1, t->subhandle) > 0) ret = t->subcode; } else { memcpy (dst, t->subdata + sector * SUB_CHANNEL_SIZE + t->suboffset, SUB_CHANNEL_SIZE); ret = t->subcode; } } if (!ret) { memset (dst, 0, SUB_CHANNEL_SIZE); // regenerate Q-subchannel uae_u8 *s = dst + 12; s[0] = (t->ctrl << 4) | (t->adr << 0); s[1] = tobcd (t - &cdu->toc[0] + 1); s[2] = tobcd (1); int msf = lsn2msf (sector); tolongbcd (s + 7, msf); msf = lsn2msf (sector - t->address - 150); tolongbcd (s + 3, msf); ret = 2; } if (ret == 1) { uae_u8 tmp[SUB_CHANNEL_SIZE]; memcpy (tmp, dst, SUB_CHANNEL_SIZE); sub_to_deinterleaved (tmp, dst); ret = 2; } uae_sem_post (&cdu->sub_sem); return ret; }
static int get_toc (void) { uae_u32 msf; uae_u8 *p, *pl; cdtvcr_4510_ram[CDTVCR_SYS_STATE] &= ~4; datatrack = 0; if (!sys_command_cd_toc (unitnum, &toc)) return 0; cdtvcr_4510_ram[CDTVCR_SYS_STATE] |= 4 | 8; if (toc.first_track == 1 && (toc.toc[toc.first_track_offset].control & 0x0c) == 0x04) datatrack = 1; p = &cdtvcr_4510_ram[CDTVCR_TOC]; cdtvcr_4510_ram[CDTVCR_PLAYLIST_CURRENT] = 0; cdtvcr_4510_ram[CDTVCR_PLAYLIST_ENTRIES] = 0; pl = &cdtvcr_4510_ram[CDTVCR_PLAYLIST_DATA]; p[0] = toc.first_track; p[1] = toc.last_track; msf = lsn2msf(toc.lastaddress); p[2] = msf >> 16; p[3] = msf >> 8; p[4] = msf >> 0; p += 5; for (int j = toc.first_track_offset; j <= toc.last_track_offset; j++) { struct cd_toc *s = &toc.toc[j]; p[0] = (s->adr << 0) | (s->control << 4); p[1] = s->track; msf = lsn2msf(s->address); p[2] = msf >> 16; p[3] = msf >> 8; p[4] = msf >> 0; p += 5; *pl++ = s->track | 0x80; cdtvcr_4510_ram[CDTVCR_PLAYLIST_ENTRIES]++; } return 1; }
/** * Parse CDDB text */ Cddb::Album& Cddb::Album::operator =(const QString& rhs) { discGenre.clear(); discID = 0; artist.clear(); title.clear(); genre.clear(); year = 0; submitter = "MythTV " MYTH_BINARY_VERSION; rev = 1; isCompilation = false; tracks.clear(); toc.clear(); extd.clear(); ext.clear(); enum { kNorm, kToc } eState = kNorm; QString cddb = QString::fromUtf8(rhs.toLatin1().constData()); while (!cddb.isEmpty()) { // Lines should be of the form "FIELD=value\r\n" QString line = cddb.section(QRegExp("[\r\n]"), 0, 0); if (line.startsWith("# Track frame offsets:")) { eState = kToc; } else if (line.startsWith("# Disc length:")) { QString s = line.section(QRegExp("[ \t]"), 3, 3); unsigned secs = s.toULong(); if (toc.size()) secs -= msf2sec(toc[0]); toc.push_back(sec2msf(secs)); eState = kNorm; } else if (line.startsWith("# Revision:")) { QString s = line.section(QRegExp("[ \t]"), 2, 2); bool bValid = false; int v = s.toInt(&bValid); if (bValid) rev = v; } else if (line.startsWith("# Submitted via:")) { submitter = line.section(QRegExp("[ \t]"), 3, 3); } else if (line.startsWith("#")) { if (kToc == eState) { bool bValid = false; QString s = line.section(QRegExp("[ \t]"), 1).trimmed(); unsigned long lsn = s.toUInt(&bValid); if (bValid) toc.push_back(lsn2msf(lsn)); else eState = kNorm; } } else { QString value = line.section('=', 1, 1); QString art; if (value.contains(" / ")) { art = value.section(" / ", 0, 0); // Artist in *TITLE value = value.section(" / ", 1, 1); } if (line.startsWith("DISCID=")) { bool isValid = false; ulong discID2 = value.toULong(&isValid,16); if (isValid) discID = discID2; } else if (line.startsWith("DTITLE=")) { // Albums (and maybe artists?) can wrap over multiple lines: artist += art; title += value; } else if (line.startsWith("DYEAR=")) { bool isValid = false; int val = value.toInt(&isValid); if (isValid) year = val; } else if (line.startsWith("DGENRE=")) { if (!value.isEmpty()) genre = value; } else if (line.startsWith("TTITLE")) { int trk = line.remove("TTITLE").section('=', 0, 0).toInt(); if (trk >= 0 && trk < CDROM_LEADOUT_TRACK) { if (trk >= tracks.size()) tracks.resize(trk + 1); Cddb::Track& track = tracks[trk]; // Titles can wrap over multiple lines, so we load+store: track.title += value; track.artist += art; if (art.length()) isCompilation = true; } } else if (line.startsWith("EXTD=")) { if (!value.isEmpty()) extd = value; } else if (line.startsWith("EXTT")) { int trk = line.remove("EXTT").section('=', 0, 0).toInt(); if (trk >= 0 && trk < CDROM_LEADOUT_TRACK) { if (trk >= ext.size()) ext.resize(trk + 1); ext[trk] = value; } } } // Next response line: cddb = cddb.section('\n', 1); } return *this; }
/* read qcode */ static int ioctl_command_qcode (int unitnum, uae_u8 *buf, int sector) { struct dev_info_ioctl *ciw = unitisopen (unitnum); if (!ciw) return 0; uae_u8 *p; int trk; CDROM_TOC *toc = &ciw->cdromtoc; int pos; int msf; int start, end; int status; bool valid = false; bool regenerate = true; memset (buf, 0, SUBQ_SIZE); p = buf; status = AUDIO_STATUS_NO_STATUS; if (ciw->cdda_play) { status = AUDIO_STATUS_IN_PROGRESS; if (ciw->cdda_paused) status = AUDIO_STATUS_PAUSED; } else if (ciw->cdda_play_finished) { status = AUDIO_STATUS_PLAY_COMPLETE; } p[1] = status; p[3] = 12; p = buf + 4; if (sector < 0) pos = ciw->cd_last_pos; else pos = sector; if (!regenerate) { if (sector < 0 && ciw->subcodevalid && ciw->cdda_play) { uae_sem_wait (&ciw->sub_sem2); uae_u8 subbuf[SUB_CHANNEL_SIZE]; sub_deinterleave (ciw->subcodebuf, subbuf); memcpy (p, subbuf + 12, 12); uae_sem_post (&ciw->sub_sem2); valid = true; } if (!valid && sector >= 0) { DWORD len; uae_sem_wait (&ciw->sub_sem); seterrormode (ciw); RAW_READ_INFO rri; rri.DiskOffset.QuadPart = 2048 * (pos + 0); rri.SectorCount = 1; rri.TrackMode = RawWithSubCode; memset (ciw->tempbuffer, 0, CD_RAW_SECTOR_WITH_SUBCODE_SIZE); if (!DeviceIoControl (ciw->h, IOCTL_CDROM_RAW_READ, &rri, sizeof rri, ciw->tempbuffer, CD_RAW_SECTOR_WITH_SUBCODE_SIZE, &len, NULL)) { DWORD err = GetLastError (); write_log (_T("IOCTL_CDROM_RAW_READ SUBQ CDDA sector %d returned %d\n"), pos, err); } reseterrormode (ciw); uae_u8 subbuf[SUB_CHANNEL_SIZE]; sub_deinterleave (ciw->tempbuffer + 2352, subbuf); uae_sem_post (&ciw->sub_sem); memcpy (p, subbuf + 12, 12); valid = true; } } if (!valid) { start = end = 0; for (trk = 0; trk <= toc->LastTrack; trk++) { TRACK_DATA *td = &toc->TrackData[trk]; start = msf2lsn ((td->Address[1] << 16) | (td->Address[2] << 8) | td->Address[3]); end = msf2lsn ((td[1].Address[1] << 16) | (td[1].Address[2] << 8) | td[1].Address[3]); if (pos < start) break; if (pos >= start && pos < end) break; } p[0] = (toc->TrackData[trk].Control << 4) | (toc->TrackData[trk].Adr << 0); p[1] = tobcd (trk + 1); p[2] = tobcd (1); msf = lsn2msf (pos); tolongbcd (p + 7, msf); msf = lsn2msf (pos - start - 150); tolongbcd (p + 3, msf); } // write_log (_T("%6d %02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x.%02x\n"), // pos, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11]); return 1; }