diff --git a/src/dos/cdrom.h b/src/dos/cdrom.h index 241839be..6242bc42 100644 --- a/src/dos/cdrom.h +++ b/src/dos/cdrom.h @@ -31,6 +31,11 @@ typedef struct SMSF { unsigned char fr; } TMSF; +typedef struct SCtrl { + Bit8u out[4]; // output channel + Bit8u vol[4]; // channel volume +} TCtrl; + extern int CDROM_GetMountType(char* path, int force); class CDROM_Interface @@ -52,6 +57,7 @@ public: virtual bool PlayAudioSector (unsigned long start,unsigned long len) = 0; virtual bool PauseAudio (bool resume) = 0; virtual bool StopAudio (void) = 0; + virtual void ChannelControl (TCtrl ctrl) = 0; virtual bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num) = 0; @@ -76,6 +82,7 @@ public: virtual bool PlayAudioSector (unsigned long start,unsigned long len); virtual bool PauseAudio (bool resume); virtual bool StopAudio (void); + virtual void ChannelControl (TCtrl ctrl) { return; }; virtual bool ReadSectors (PhysPt /*buffer*/, bool /*raw*/, unsigned long /*sector*/, unsigned long /*num*/) { return false; }; virtual bool LoadUnloadMedia (bool unload); @@ -101,6 +108,7 @@ public: bool PlayAudioSector (unsigned long /*start*/,unsigned long /*len*/) { return true; }; bool PauseAudio (bool /*resume*/) { return true; }; bool StopAudio (void) { return true; }; + void ChannelControl (TCtrl ctrl) { return; }; bool ReadSectors (PhysPt /*buffer*/, bool /*raw*/, unsigned long /*sector*/, unsigned long /*num*/) { return true; }; bool LoadUnloadMedia (bool /*unload*/) { return true; }; }; @@ -166,6 +174,7 @@ public: bool PlayAudioSector (unsigned long start,unsigned long len); bool PauseAudio (bool resume); bool StopAudio (void); + void ChannelControl (TCtrl ctrl); bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); bool LoadUnloadMedia (bool unload); bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector); @@ -188,6 +197,8 @@ static struct imagePlayer { int targetFrame; bool isPlaying; bool isPaused; + bool ctrlUsed; + TCtrl ctrlData; } player; void ClearTracks(); @@ -234,6 +245,7 @@ public: bool PlayAudioSector (unsigned long start,unsigned long len); bool PauseAudio (bool resume); bool StopAudio (void); + void ChannelControl (TCtrl ctrl) { return; }; bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); @@ -284,6 +296,7 @@ public: bool PlayAudioSector (unsigned long start,unsigned long len); bool PauseAudio (bool resume); bool StopAudio (void); + void ChannelControl (TCtrl ctrl); bool ReadSector (Bit8u *buffer, bool raw, unsigned long sector); bool ReadSectors (PhysPt buffer, bool raw, unsigned long sector, unsigned long num); @@ -338,6 +351,8 @@ private: int targetFrame; bool isPlaying; bool isPaused; + bool ctrlUsed; + TCtrl ctrlData; } player; }; diff --git a/src/dos/cdrom_image.cpp b/src/dos/cdrom_image.cpp index d7bcfa66..26375c9a 100644 --- a/src/dos/cdrom_image.cpp +++ b/src/dos/cdrom_image.cpp @@ -131,7 +131,7 @@ int CDROM_Interface_Image::AudioFile::getLength() int CDROM_Interface_Image::refCount = 0; CDROM_Interface_Image* CDROM_Interface_Image::images[26]; CDROM_Interface_Image::imagePlayer CDROM_Interface_Image::player = { - NULL, NULL, NULL, {0}, 0, 0, 0, false, false }; + NULL, NULL, NULL, {0}, 0, 0, 0, false, false, false, {0} }; CDROM_Interface_Image::CDROM_Interface_Image(Bit8u subUnit) @@ -259,6 +259,12 @@ bool CDROM_Interface_Image::StopAudio(void) return true; } +void CDROM_Interface_Image::ChannelControl(TCtrl ctrl) +{ + player.ctrlUsed = (ctrl.out[0]!=0 || ctrl.out[1]!=1 || ctrl.vol[0]<0xfe || ctrl.vol[1]<0xfe); + player.ctrlData = ctrl; +} + bool CDROM_Interface_Image::ReadSectors(PhysPt buffer, bool raw, unsigned long sector, unsigned long num) { int sectorSize = raw ? RAW_SECTOR_SIZE : COOKED_SECTOR_SIZE; @@ -336,6 +342,16 @@ void CDROM_Interface_Image::CDAudioCallBack(Bitu len) } } SDL_mutexV(player.mutex); + if (player.ctrlUsed) { + Bit16s sample0,sample1; + Bit16s * samples=(Bit16s *)&player.buffer; + for (Bitu pos=0;posAddSamples_s16_nonnative(len/4,(Bit16s *)player.buffer); #else diff --git a/src/dos/cdrom_ioctl_win32.cpp b/src/dos/cdrom_ioctl_win32.cpp index 9044e543..c12f7526 100644 --- a/src/dos/cdrom_ioctl_win32.cpp +++ b/src/dos/cdrom_ioctl_win32.cpp @@ -175,7 +175,7 @@ bool CDROM_Interface_Ioctl::mci_CDPosition(int *position) { CDROM_Interface_Ioctl::dxPlayer CDROM_Interface_Ioctl::player = { - NULL, NULL, NULL, 0, 0, 0, 0, 0, false, false }; + NULL, NULL, NULL, {0}, 0, 0, 0, false, false, false, {0} }; CDROM_Interface_Ioctl::CDROM_Interface_Ioctl(cdioctl_cdatype ioctl_cda) { pathname[0] = 0; @@ -462,6 +462,12 @@ bool CDROM_Interface_Ioctl::StopAudio(void) { return bStat>0; } +void CDROM_Interface_Ioctl::ChannelControl(TCtrl ctrl) +{ + player.ctrlUsed = (ctrl.out[0]!=0 || ctrl.out[1]!=1 || ctrl.vol[0]<0xfe || ctrl.vol[1]<0xfe); + player.ctrlData = ctrl; +} + bool CDROM_Interface_Ioctl::LoadUnloadMedia(bool unload) { BOOL bStat; DWORD byteCount; @@ -553,6 +559,16 @@ void CDROM_Interface_Ioctl::dx_CDAudioCallBack(Bitu len) { } } SDL_mutexV(player.mutex); + if (player.ctrlUsed) { + Bit16s sample0,sample1; + Bit16s * samples=(Bit16s *)&player.buffer; + for (Bitu pos=0;posAddSamples_s16(len/4,(Bit16s *)player.buffer); memmove(player.buffer, &player.buffer[len], player.bufLen - len); player.bufLen -= len; diff --git a/src/dos/dos_mscdex.cpp b/src/dos/dos_mscdex.cpp index 5800fd1f..b0f011f6 100644 --- a/src/dos/dos_mscdex.cpp +++ b/src/dos/dos_mscdex.cpp @@ -152,6 +152,7 @@ private: bool locked; // drive locked ? bool lastResult; // last operation success ? Bit32u volumeSize; // for media change + TCtrl audioCtrl; // audio channel control } TDriveInfo; Bit16u defaultBufSeg; @@ -160,6 +161,9 @@ private: public: Bit16u rootDriverHeaderSeg; + + bool ChannelControl (Bit8u subUnit, TCtrl ctrl); + bool GetChannelControl (Bit8u subUnit, TCtrl& ctrl); }; CMscdex::CMscdex(void) { @@ -391,6 +395,11 @@ int CMscdex::AddDrive(Bit16u _drive, char* physicalPath, Bit8u& subUnit) subUnit = (Bit8u)numDrives; } numDrives++; + // init channel control + for (Bit8u chan=0;chan<4;chan++) { + dinfo[subUnit].audioCtrl.out[chan]=chan; + dinfo[subUnit].audioCtrl.vol[chan]=0xff; + } // stop audio StopAudio(subUnit); return result; @@ -463,7 +472,7 @@ bool CMscdex::PlayAudioSector(Bit8u subUnit, Bit32u sector, Bit32u length) if (subUnit>=numDrives) return false; // If value from last stop is used, this is meant as a resume // better start using resume command - if (dinfo[subUnit].audioPaused && (sector==dinfo[subUnit].audioStart)) { + if (dinfo[subUnit].audioPaused && (sector==dinfo[subUnit].audioStart) && (dinfo[subUnit].audioEnd!=0)) { dinfo[subUnit].lastResult = cdrom[subUnit]->PauseAudio(true); } else dinfo[subUnit].lastResult = cdrom[subUnit]->PlayAudioSector(sector,length); @@ -800,6 +809,7 @@ Bit32u CMscdex::GetDeviceStatus(Bit8u subUnit) (dinfo[subUnit].locked << 1) | // Drive is locked ? (1<<2) | // raw + cooked sectors (1<<4) | // Can read sudio + (1<<8) | // Can control audio (1<<9) | // Red book & HSG ((!media) << 11); // Drive is empty ? return status; @@ -864,6 +874,22 @@ void CMscdex::InitNewMedia(Bit8u subUnit) { } } +bool CMscdex::ChannelControl(Bit8u subUnit, TCtrl ctrl) { + if (subUnit>=numDrives) return false; + // adjust strange channel mapping + if (ctrl.out[0]>1) ctrl.out[0]=0; + if (ctrl.out[1]>1) ctrl.out[1]=1; + dinfo[subUnit].audioCtrl=ctrl; + cdrom[subUnit]->ChannelControl(ctrl); + return true; +} + +bool CMscdex::GetChannelControl(Bit8u subUnit, TCtrl& ctrl) { + if (subUnit>=numDrives) return false; + ctrl=dinfo[subUnit].audioCtrl; + return true; +} + static CMscdex* mscdex = 0; static PhysPt curReqheaderPtr = 0; @@ -893,6 +919,14 @@ static Bit16u MSCDEX_IOCTL_Input(PhysPt buffer,Bit8u drive_unit) { return 0x03; // invalid function } }break; + case 0x04 : /* Audio Channel control */ + TCtrl ctrl; + if (!mscdex->GetChannelControl(drive_unit,ctrl)) return 0x01; + for (Bit8u chan=0;chan<4;chan++) { + mem_writeb(buffer+chan*2+1,ctrl.out[chan]); + mem_writeb(buffer+chan*2+2,ctrl.vol[chan]); + } + break; case 0x06 : /* Get Device status */ mem_writed(buffer+1,mscdex->GetDeviceStatus(drive_unit)); break; @@ -984,7 +1018,13 @@ static Bit16u MSCDEX_IOCTL_Optput(PhysPt buffer,Bit8u drive_unit) { if (!mscdex->LoadUnloadMedia(drive_unit,true)) return 0x02; break; case 0x03: //Audio Channel control - MSCDEX_LOG("MSCDEX: Audio Channel Control used. Not handled. Faking succes!"); + TCtrl ctrl; + for (Bit8u chan=0;chan<4;chan++) { + ctrl.out[chan]=mem_readb(buffer+chan*2+1); + ctrl.vol[chan]=mem_readb(buffer+chan*2+2); + } + if (!mscdex->ChannelControl(drive_unit,ctrl)) return 0x01; + break; case 0x01 : // (un)Lock door // do nothing -> report as success break;