- removed Windows CD Audio support.

Better get rid of this legacy baggage now, before it is too later.
This commit is contained in:
Christoph Oelckers 2020-02-18 21:44:21 +01:00
parent 26f87a5055
commit fb0abfcd08
8 changed files with 0 additions and 1465 deletions

View file

@ -301,7 +301,6 @@ extern "C"
ZMUSIC_DLL_IMPORT ZMusic_MusicStream ZMusic_OpenSong(ZMusicCustomReader* reader, EZMusicMidiDevice device, const char* Args);
ZMUSIC_DLL_IMPORT ZMusic_MusicStream ZMusic_OpenSongFile(const char *filename, EZMusicMidiDevice device, const char* Args);
ZMUSIC_DLL_IMPORT ZMusic_MusicStream ZMusic_OpenSongMem(const void *mem, size_t size, EZMusicMidiDevice device, const char* Args);
ZMUSIC_DLL_IMPORT ZMusic_MusicStream ZMusic_OpenCDSong(int track, int cdid);
ZMUSIC_DLL_IMPORT zmusic_bool ZMusic_FillStream(ZMusic_MusicStream stream, void* buff, int len);
ZMUSIC_DLL_IMPORT zmusic_bool ZMusic_Start(ZMusic_MusicStream song, int subsong, zmusic_bool loop);
@ -335,16 +334,6 @@ extern "C"
ZMUSIC_DLL_IMPORT const ZMusicMidiOutDevice *ZMusic_GetMidiDevices(int *pAmount);
ZMUSIC_DLL_IMPORT int ZMusic_GetADLBanks(const char* const** pNames);
// Direct access to the CD drive.
ZMUSIC_DLL_IMPORT void ZMusic_CD_Stop();
ZMUSIC_DLL_IMPORT void ZMusic_CD_Pause();
ZMUSIC_DLL_IMPORT zmusic_bool ZMusic_CD_Resume();
ZMUSIC_DLL_IMPORT void ZMusic_CD_Eject();
ZMUSIC_DLL_IMPORT zmusic_bool ZMusic_CD_UnEject();
ZMUSIC_DLL_IMPORT void ZMusic_CD_Close();
ZMUSIC_DLL_IMPORT zmusic_bool ZMusic_CD_Enable(const char* drive);
#ifdef __cplusplus
}

View file

@ -62,8 +62,6 @@ include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/
if (WIN32)
set( PLAT_SOURCES
mididevices/music_win_mididevice.cpp
musicformats/win32/i_cd.cpp
musicformats/win32/helperthread.cpp
)
elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if (ALSA_FOUND)
@ -81,7 +79,6 @@ file( GLOB HEADER_FILES
mididevices/*.h
midisources/*.h
musicformats/*.h
musicformats/win32/*.h
decoder/*.h
streamsources/*.h
../thirdparty/*.h
@ -112,7 +109,6 @@ set( all_files
streamsources/music_xa.cpp
musicformats/music_stream.cpp
musicformats/music_midi.cpp
musicformats/music_cd.cpp
decoder/sounddecoder.cpp
decoder/sndfile_decoder.cpp
decoder/mpg123_decoder.cpp

View file

@ -1,210 +0,0 @@
/*
** music_cd.cpp
**
**---------------------------------------------------------------------------
** Copyright 1999-2003 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "zmusic/zmusic_internal.h"
#include "zmusic/musinfo.h"
#ifdef _WIN32
#include "zmusic/m_swap.h"
#include "win32/i_cd.h"
// CD track/disk played through the multimedia system -----------------------
class CDSong : public MusInfo
{
public:
CDSong(int track, int id);
~CDSong();
void Play(bool looping, int subsong);
void Pause();
void Resume();
void Stop();
bool IsPlaying();
bool IsValid() const { return m_Inited; }
protected:
CDSong() : m_Inited(false) {}
int m_Track;
bool m_Inited;
};
// CD track on a specific disk played through the multimedia system ---------
class CDDAFile : public CDSong
{
public:
CDDAFile(MusicIO::FileInterface* reader);
};
void CDSong::Play (bool looping, int subsong)
{
m_Status = STATE_Stopped;
m_Looping = looping;
if (m_Track != 0 ? CD_Play (m_Track, looping) : CD_PlayCD (looping))
{
m_Status = STATE_Playing;
}
}
void CDSong::Pause ()
{
if (m_Status == STATE_Playing)
{
ZMusic_CD_Pause ();
m_Status = STATE_Paused;
}
}
void CDSong::Resume ()
{
if (m_Status == STATE_Paused)
{
if (ZMusic_CD_Resume ())
m_Status = STATE_Playing;
}
}
void CDSong::Stop ()
{
if (m_Status != STATE_Stopped)
{
m_Status = STATE_Stopped;
ZMusic_CD_Stop ();
}
}
CDSong::~CDSong ()
{
Stop ();
m_Inited = false;
}
CDSong::CDSong (int track, int id)
{
bool success;
m_Inited = false;
if (id != 0)
{
success = CD_InitID (id);
}
else
{
success = CD_Init (-1);
}
if (success && (track == 0 || CD_CheckTrack (track)))
{
m_Inited = true;
m_Track = track;
}
}
bool CDSong::IsPlaying ()
{
if (m_Status == STATE_Playing)
{
if (CD_GetMode () != CDMode_Play)
{
Stop ();
}
}
return m_Status != STATE_Stopped;
}
CDDAFile::CDDAFile (MusicIO::FileInterface* reader)
: CDSong ()
{
uint32_t chunk;
uint16_t track;
uint32_t discid;
auto endpos = reader->tell() + reader->filelength() - 8;
// ZMusic_OpenSong already identified this as a CDDA file, so we
// just need to check the contents we're interested in.
reader->seek(12, SEEK_CUR);
while (reader->tell() < endpos)
{
reader->read(&chunk, 4);
if (chunk != (('f')|(('m')<<8)|(('t')<<16)|((' ')<<24)))
{
reader->read(&chunk, 4);
reader->seek(LittleLong(chunk), SEEK_CUR);
}
else
{
reader->seek(6, SEEK_CUR);
reader->read(&track, 2);
reader->read(&discid, 4);
if (CD_InitID (LittleLong(discid)) && CD_CheckTrack (LittleShort(track)))
{
m_Inited = true;
m_Track = track;
}
return;
}
}
}
MusInfo* CD_OpenSong(int track, int id)
{
return new CDSong(track, id);
}
MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader)
{
return new CDDAFile(reader);
}
#else
MusInfo* CD_OpenSong(int track, int id)
{
return nullptr;
}
MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader)
{
return nullptr;
}
#endif

View file

@ -1,292 +0,0 @@
/*
** helperthread.cpp
**
** Implements FHelperThread, the base class for helper threads. Includes
** a message queue for passing messages from the main thread to the
** helper thread. (Only used by the CD Audio player)
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#include "helperthread.h"
//==========================================================================
//
// ---Constructor---
//
//==========================================================================
FHelperThread::FHelperThread ()
{
ThreadHandle = NULL;
ThreadID = 0;
Thread_Events[0] = Thread_Events[1] = 0;
memset (Messages, 0, sizeof(Messages));
MessageHead = 0;
MessageTail = 0;
}
//==========================================================================
//
// ---Destructor---
//
//==========================================================================
FHelperThread::~FHelperThread ()
{
DestroyThread ();
}
//==========================================================================
//
// LaunchThread
//
//==========================================================================
bool FHelperThread::LaunchThread ()
{
int i;
MessageHead = MessageTail = 0;
for (i = 0; i < MSG_QUEUE_SIZE; i++)
{
if ((Messages[i].CompletionEvent = CreateEvent (NULL, FALSE, i > 0, NULL)) == NULL)
break;
}
if (i < MSG_QUEUE_SIZE)
{
for (; i >= 0; i--)
{
CloseHandle (Messages[i].CompletionEvent);
}
return false;
}
InitializeCriticalSection (&Thread_Critical);
if ((Thread_Events[0] = CreateEvent (NULL, TRUE, FALSE, NULL)))
{
if ((Thread_Events[1] = CreateEvent (NULL, TRUE, FALSE, NULL)))
{
if ((ThreadHandle = CreateThread (NULL, 0, ThreadLaunch, (LPVOID)this, 0, &ThreadID)))
{
HANDLE waiters[2] = { Messages[0].CompletionEvent, ThreadHandle };
if (WaitForMultipleObjects (2, waiters, FALSE, INFINITE) == WAIT_OBJECT_0+1)
{ // Init failed, and the thread exited
DestroyThread ();
return false;
}
#if defined(_MSC_VER) && defined(_DEBUG)
// Give the thread a name in the debugger
struct
{
DWORD type;
LPCSTR name;
DWORD threadID;
DWORD flags;
} info =
{
0x1000, ThreadName(), ThreadID, 0
};
__try
{
RaiseException( 0x406D1388, 0, sizeof(info)/sizeof(DWORD), (ULONG_PTR *)&info );
}
__except(EXCEPTION_CONTINUE_EXECUTION)
{
}
#endif
return true;
}
CloseHandle (Thread_Events[1]);
}
CloseHandle (Thread_Events[0]);
}
DeleteCriticalSection (&Thread_Critical);
for (i = 0; i < MSG_QUEUE_SIZE; i++)
{
CloseHandle (Messages[i].CompletionEvent);
}
return false;
}
//==========================================================================
//
// DestroyThread
//
//==========================================================================
void FHelperThread::DestroyThread ()
{
int i;
if (ThreadHandle == NULL)
return;
SetEvent (Thread_Events[THREAD_KillSelf]);
// 5 seconds should be sufficient. If not, then we'll crash, but at
// least that's better than hanging indefinitely.
WaitForSingleObject (ThreadHandle, 5000);
CloseHandle (ThreadHandle);
EnterCriticalSection (&Thread_Critical);
for (i = 0; i < 8; i++)
{
CloseHandle (Messages[i].CompletionEvent);
}
CloseHandle (Thread_Events[0]);
CloseHandle (Thread_Events[1]);
LeaveCriticalSection (&Thread_Critical);
DeleteCriticalSection (&Thread_Critical);
ThreadHandle = NULL;
}
//==========================================================================
//
// HaveThread
//
//==========================================================================
bool FHelperThread::HaveThread () const
{
return ThreadHandle != NULL;
}
//==========================================================================
//
// SendMessage
//
//==========================================================================
DWORD FHelperThread::SendMessage (DWORD method,
DWORD parm1, DWORD parm2, DWORD parm3, bool wait)
{
for (;;)
{
EnterCriticalSection (&Thread_Critical);
if (MessageHead - MessageTail == MSG_QUEUE_SIZE)
{ // No room, so wait for oldest message to complete
HANDLE waitEvent = Messages[MessageTail].CompletionEvent;
LeaveCriticalSection (&Thread_Critical);
WaitForSingleObject (waitEvent, 1000);
}
int head = MessageHead++ % MSG_QUEUE_SIZE;
Messages[head].Method = method;
Messages[head].Parm1 = parm1;
Messages[head].Parm2 = parm2;
Messages[head].Parm3 = parm3;
ResetEvent (Messages[head].CompletionEvent);
LeaveCriticalSection (&Thread_Critical);
SetEvent (Thread_Events[THREAD_NewMessage]);
if (wait)
{
WaitForSingleObject (Messages[head].CompletionEvent, INFINITE);
return Messages[head].Return;
}
return 0;
}
}
//==========================================================================
//
// ThreadLaunch (static)
//
//==========================================================================
DWORD WINAPI FHelperThread::ThreadLaunch (LPVOID me)
{
return ((FHelperThread *)me)->ThreadLoop ();
}
//==========================================================================
//
// ThreadLoop
//
//==========================================================================
DWORD FHelperThread::ThreadLoop ()
{
if (!Init ())
{
ExitThread (0);
}
else
{
SetEvent (Messages[0].CompletionEvent);
}
for (;;)
{
switch (MsgWaitForMultipleObjects (2, Thread_Events,
FALSE, INFINITE, QS_ALLEVENTS))
{
case WAIT_OBJECT_0+1:
// We should quit now.
Deinit ();
ExitThread (0);
break;
case WAIT_OBJECT_0:
// Process any new messages. MessageTail is not updated until *after*
// the message is finished processing.
for (;;)
{
EnterCriticalSection (&Thread_Critical);
if (MessageHead == MessageTail)
{
ResetEvent (Thread_Events[0]);
LeaveCriticalSection (&Thread_Critical);
break; // Resume outer for (Wait for more messages)
}
int spot = MessageTail % MSG_QUEUE_SIZE;
LeaveCriticalSection (&Thread_Critical);
Messages[spot].Return = Dispatch (Messages[spot].Method,
Messages[spot].Parm1, Messages[spot].Parm2,
Messages[spot].Parm3);
// No need to enter critical section, because only the CD thread
// is allowed to touch MessageTail or signal the CompletionEvent
SetEvent (Messages[spot].CompletionEvent);
MessageTail++;
}
break;
default:
DefaultDispatch ();
}
}
}

View file

@ -1,85 +0,0 @@
/*
** helperthread.h
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef __HELPERTHREAD_H__
#define __HELPERTHREAD_H__
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
class FHelperThread
{
struct Message
{
DWORD Method;
DWORD Parm1, Parm2, Parm3;
HANDLE CompletionEvent; // Set to signalled when message is finished processing
DWORD Return;
};
enum { MSG_QUEUE_SIZE = 8 };
public:
FHelperThread ();
virtual ~FHelperThread ();
void DestroyThread ();
bool LaunchThread ();
DWORD SendMessage (DWORD method, DWORD parm1, DWORD parm2,
DWORD parm3, bool wait);
bool HaveThread () const;
protected:
enum EThreadEvents { THREAD_NewMessage, THREAD_KillSelf };
virtual bool Init () { return true; }
virtual void Deinit () {}
virtual void DefaultDispatch () {}
virtual DWORD Dispatch (DWORD method, DWORD parm1=0, DWORD parm2=0, DWORD parm3=0) = 0;
virtual const char *ThreadName () = 0;
HANDLE ThreadHandle;
DWORD ThreadID;
HANDLE Thread_Events[2];
CRITICAL_SECTION Thread_Critical;
Message Messages[MSG_QUEUE_SIZE];
DWORD MessageHead;
DWORD MessageTail;
private:
void ReleaseSynchronizers ();
static DWORD WINAPI ThreadLaunch (LPVOID me);
DWORD ThreadLoop ();
};
#endif //__HELPERTHREAD_H__

View file

@ -1,762 +0,0 @@
/*
** i_cd.cpp
** Functions for controlling CD playback
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <stdlib.h>
#include "zmusic_internal.h"
#include "helperthread.h"
#include "i_cd.h"
enum
{
CDM_Init, // parm1 = device
CDM_Close,
CDM_Play, // parm1 = track, parm2 = 1:looping
CDM_PlayCD, // parm1 = 1:looping
CDM_Replay, // Redos the most recent CDM_Play(CD)
CDM_Stop,
CDM_Eject,
CDM_UnEject,
CDM_Pause,
CDM_Resume,
CDM_GetMode,
CDM_CheckTrack, // parm1 = track
CDM_GetMediaIdentity,
CDM_GetMediaUPC
};
class FCDThread : public FHelperThread
{
public:
FCDThread ();
protected:
bool Init ();
void Deinit ();
const char *ThreadName ();
DWORD Dispatch (DWORD method, DWORD parm1=0, DWORD parm2=0, DWORD parm3=0);
void DefaultDispatch ();
bool IsTrackAudio (DWORD track) const;
DWORD GetTrackLength (DWORD track) const;
DWORD GetNumTracks () const;
static LRESULT CALLBACK CD_WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
WNDCLASS CD_WindowClass;
HWND CD_Window;
ATOM CD_WindowAtom;
bool Looping;
DWORD PlayFrom;
DWORD PlayTo;
UINT DeviceID;
};
#define NOT_INITED ((signed)0x80000000)
static FCDThread *CDThread;
static int Inited = NOT_INITED;
static int Enabled = false;
//==========================================================================
//
// ---Constructor---
//
//==========================================================================
FCDThread::FCDThread ()
{
memset (&CD_WindowClass, 0, sizeof(CD_WindowClass));
CD_Window = NULL;
CD_WindowAtom = 0;
Inited = NOT_INITED;
Looping = false;
PlayFrom = 0;
PlayTo = 0;
DeviceID = 0;
LaunchThread ();
}
//==========================================================================
//
// ThreadName
//
//==========================================================================
const char *FCDThread::ThreadName ()
{
return "CD Player";
}
//==========================================================================
//
// Init
//
//==========================================================================
bool FCDThread::Init ()
{
CD_WindowClass.style = CS_NOCLOSE;
CD_WindowClass.lpfnWndProc = CD_WndProc;
CD_WindowClass.hInstance = GetModuleHandle(nullptr);
CD_WindowClass.lpszClassName = L"ZMusic CD Player";
CD_WindowAtom = RegisterClass (&CD_WindowClass);
if (CD_WindowAtom == 0)
return false;
CD_Window = CreateWindow (
(LPCTSTR)(INT_PTR)(int)CD_WindowAtom,
CD_WindowClass.lpszClassName,
0,
0, 0, 10, 10,
NULL,
NULL,
CD_WindowClass.hInstance,
NULL);
if (CD_Window == NULL)
{
UnregisterClass ((LPCTSTR)(INT_PTR)(int)CD_WindowAtom, CD_WindowClass.hInstance);
CD_WindowAtom = 0;
return false;
}
#ifdef _WIN64
SetWindowLongPtr (CD_Window, GWLP_USERDATA, (LONG_PTR)this);
#else
SetWindowLong (CD_Window, GWL_USERDATA, (LONG)(LONG_PTR)this);
#endif
SetThreadPriority (ThreadHandle, THREAD_PRIORITY_LOWEST);
return true;
}
//==========================================================================
//
// Deinit
//
//==========================================================================
void FCDThread::Deinit ()
{
if (CD_Window)
{
DestroyWindow (CD_Window);
CD_Window = NULL;
}
if (CD_WindowAtom)
{
UnregisterClass ((LPCTSTR)(INT_PTR)(int)CD_WindowAtom, GetModuleHandle(nullptr));
CD_WindowAtom = 0;
}
if (DeviceID)
{
Dispatch (CDM_Close);
}
}
//==========================================================================
//
// DefaultDispatch
//
//==========================================================================
void FCDThread::DefaultDispatch ()
{
MSG wndMsg;
while (PeekMessage (&wndMsg, NULL, 0, 0, PM_REMOVE))
{
DispatchMessage (&wndMsg);
}
}
//==========================================================================
//
// Dispatch
//
// Does the actual work of implementing the public CD interface
//
//==========================================================================
DWORD FCDThread::Dispatch (DWORD method, DWORD parm1, DWORD parm2, DWORD parm3)
{
MCI_OPEN_PARMS mciOpen;
MCI_SET_PARMS mciSetParms;
MCI_PLAY_PARMS playParms;
MCI_STATUS_PARMS statusParms;
MCI_INFO_PARMS infoParms;
DWORD firstTrack, lastTrack, numTracks;
DWORD length;
DWORD openFlags;
wchar_t ident[32];
switch (method)
{
case CDM_Init:
mciOpen.lpstrDeviceType = (LPCWSTR)MCI_DEVTYPE_CD_AUDIO;
openFlags = MCI_OPEN_SHAREABLE|MCI_OPEN_TYPE|MCI_OPEN_TYPE_ID|MCI_WAIT;
if ((signed)parm1 >= 0)
{
ident[0] = (char)(parm1 + 'A');
ident[1] = ':';
ident[2] = 0;
mciOpen.lpstrElementName = ident;
openFlags |= MCI_OPEN_ELEMENT;
}
while (mciSendCommand (0, MCI_OPEN, openFlags, (DWORD_PTR)&mciOpen) != 0)
{
if (!(openFlags & MCI_OPEN_ELEMENT))
{
return FALSE;
}
openFlags &= ~MCI_OPEN_ELEMENT;
}
DeviceID = mciOpen.wDeviceID;
mciSetParms.dwTimeFormat = MCI_FORMAT_TMSF;
if (mciSendCommand (DeviceID, MCI_SET, MCI_SET_TIME_FORMAT, (DWORD_PTR)&mciSetParms) == 0)
{
return TRUE;
}
mciSendCommand (DeviceID, MCI_CLOSE, 0, 0);
return FALSE;
case CDM_Close:
Dispatch (CDM_Stop);
mciSendCommand (DeviceID, MCI_CLOSE, 0, 0);
DeviceID = 0;
return 0;
case CDM_Play:
if (!IsTrackAudio (parm1))
{
//Printf ("Track %d is not audio\n", track);
return FALSE;
}
length = GetTrackLength (parm1);
if (length == 0)
{ // Couldn't get length of track, so won't be able to play last track
PlayTo = MCI_MAKE_TMSF (parm1+1, 0, 0, 0);
}
else
{
PlayTo = MCI_MAKE_TMSF (parm1,
MCI_MSF_MINUTE(length),
MCI_MSF_SECOND(length),
MCI_MSF_FRAME(length));
}
PlayFrom = MCI_MAKE_TMSF (parm1, 0, 0, 0);
Looping = parm2 & 1;
// intentional fall-through
case CDM_Replay:
playParms.dwFrom = PlayFrom;
playParms.dwTo = PlayTo;
playParms.dwCallback = (DWORD_PTR)CD_Window;
return mciSendCommand (DeviceID, MCI_PLAY, MCI_FROM | MCI_TO | MCI_NOTIFY,
(DWORD_PTR)&playParms);
case CDM_PlayCD:
numTracks = GetNumTracks ();
if (numTracks == 0)
return FALSE;
for (firstTrack = 1; firstTrack <= numTracks && !IsTrackAudio (firstTrack); firstTrack++)
;
for (lastTrack = firstTrack; lastTrack <= numTracks && IsTrackAudio (lastTrack); lastTrack++)
;
if (firstTrack > numTracks)
return FALSE;
if (lastTrack > numTracks)
lastTrack = numTracks;
length = GetTrackLength (lastTrack);
if (length == 0)
return FALSE;
Looping = parm1 & 1;
PlayFrom = MCI_MAKE_TMSF (firstTrack, 0, 0, 0);
PlayTo = MCI_MAKE_TMSF (lastTrack,
MCI_MSF_MINUTE(length),
MCI_MSF_SECOND(length),
MCI_MSF_FRAME(length));
playParms.dwFrom = PlayFrom;
playParms.dwTo = PlayTo;
playParms.dwCallback = (DWORD_PTR)CD_Window;
return mciSendCommand (DeviceID, MCI_PLAY, MCI_FROM|MCI_TO|MCI_NOTIFY,
(DWORD_PTR)&playParms);
case CDM_Stop:
return mciSendCommand (DeviceID, MCI_STOP, 0, 0);
case CDM_Eject:
return mciSendCommand (DeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0);
case CDM_UnEject:
return mciSendCommand (DeviceID, MCI_SET, MCI_SET_DOOR_CLOSED, 0);
case CDM_Pause:
return mciSendCommand (DeviceID, MCI_PAUSE, 0, 0);
case CDM_Resume:
playParms.dwTo = PlayTo;
playParms.dwCallback = (DWORD_PTR)CD_Window;
return mciSendCommand (DeviceID, MCI_PLAY, MCI_TO | MCI_NOTIFY, (DWORD_PTR)&playParms);
case CDM_GetMode:
statusParms.dwItem = MCI_STATUS_MODE;
if (mciSendCommand (DeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&statusParms))
{
return CDMode_Unknown;
}
else
{
switch (statusParms.dwReturn)
{
case MCI_MODE_NOT_READY: return CDMode_NotReady;
case MCI_MODE_PAUSE: return CDMode_Pause;
case MCI_MODE_PLAY: return CDMode_Play;
case MCI_MODE_STOP: return CDMode_Stop;
case MCI_MODE_OPEN: return CDMode_Open;
default: return CDMode_Unknown;
}
}
case CDM_CheckTrack:
return IsTrackAudio (parm1) ? TRUE : FALSE;
case CDM_GetMediaIdentity:
case CDM_GetMediaUPC:
wchar_t ident[32];
infoParms.lpstrReturn = ident;
infoParms.dwRetSize = sizeof(ident);
if (mciSendCommand (DeviceID, MCI_INFO,
method == CDM_GetMediaIdentity ? MCI_WAIT|MCI_INFO_MEDIA_IDENTITY
: MCI_WAIT|MCI_INFO_MEDIA_UPC, (DWORD_PTR)&infoParms))
{
return 0;
}
else
{
return wcstoul (ident, NULL, 0);
}
default:
return 0;
}
}
//==========================================================================
//
// KillThread
//
//==========================================================================
static void KillThread ()
{
if (CDThread != NULL)
{
CDThread->DestroyThread ();
Inited = NOT_INITED;
delete CDThread;
}
}
//==========================================================================
//
// CD_Init
//
//==========================================================================
DLL_EXPORT zmusic_bool ZMusic_CD_Enable (const char *cd_drive)
{
if (!cd_drive)
{
// lock the CD system.
Enabled = false;
ZMusic_CD_Close();
return false;
}
Enabled = true; // this must have been called at least once to consider the use of the CD system
if ((cd_drive)[0] == 0 || (cd_drive)[1] != 0)
{
return CD_Init (-1);
}
else
{
char drive = toupper ((cd_drive)[0]);
if (drive >= 'A' && drive <= 'Z' && !CD_Init(drive - 'A'))
{
return CD_Init(-1);
}
}
return true;
}
bool CD_Init (int device)
{
if (!Enabled) return false;
if (CDThread == NULL)
{
CDThread = new FCDThread;
atexit (KillThread);
}
if (Inited != device)
{
ZMusic_CD_Close ();
if (CDThread->SendMessage (CDM_Init, device, 0, 0, true))
{
Inited = device;
return true;
}
else
{
return false;
}
}
return true;
}
//==========================================================================
//
// CD_InitID
//
//==========================================================================
bool CD_InitID (unsigned int id, int guess)
{
char drive;
if (guess < 0 && Inited != NOT_INITED)
guess = Inited;
if (guess >= 0 && CD_Init (guess))
{
if (CDThread->SendMessage (CDM_GetMediaIdentity, 0, 0, 0, true) == id ||
CDThread->SendMessage (CDM_GetMediaUPC, 0, 0, 0, true) == id)
{
return true;
}
ZMusic_CD_Close ();
}
for (drive = 'V'; drive < 'Z'; drive++)
{
if (CD_Init (drive - 'A'))
{
// I don't know which value is stored in a CDDA file, so I try
// them both. All the CDs I've tested have had the same value
// for both, so it probably doesn't matter.
if (CDThread->SendMessage (CDM_GetMediaIdentity, 0, 0, 0, true) == id ||
CDThread->SendMessage (CDM_GetMediaUPC, 0, 0, 0, true) == id)
{
return true;
}
ZMusic_CD_Close ();
}
}
return false;
}
//==========================================================================
//
// ZMusic_CD_Close
//
//==========================================================================
DLL_EXPORT void ZMusic_CD_Close ()
{
if (Inited != NOT_INITED)
{
CDThread->SendMessage (CDM_Close, 0, 0, 0, true);
Inited = NOT_INITED;
}
}
//==========================================================================
//
// ZMusic_CD_Eject
//
//==========================================================================
DLL_EXPORT void ZMusic_CD_Eject ()
{
if (Inited != NOT_INITED)
CDThread->SendMessage (CDM_Eject, 0, 0, 0, false);
}
//==========================================================================
//
// ZMusic_CD_UnEject
//
//==========================================================================
DLL_EXPORT zmusic_bool ZMusic_CD_UnEject ()
{
if (Inited == NOT_INITED)
return false;
return CDThread->SendMessage (CDM_UnEject, 0, 0, 0, true) == 0;
}
//==========================================================================
//
// ZMusic_CD_Stop
//
//==========================================================================
DLL_EXPORT void ZMusic_CD_Stop ()
{
if (Inited != NOT_INITED)
CDThread->SendMessage (CDM_Stop, 0, 0, 0, false);
}
//==========================================================================
//
// CD_Play
//
//==========================================================================
bool CD_Play (int track, bool looping)
{
if (Inited == NOT_INITED)
return false;
return CDThread->SendMessage (CDM_Play, track, looping ? 1 : 0, 0, true) == 0;
}
//==========================================================================
//
// CD_PlayNoWait
//
//==========================================================================
void CD_PlayNoWait (int track, bool looping)
{
if (Inited != NOT_INITED)
CDThread->SendMessage (CDM_Play, track, looping ? 1 : 0, 0, false);
}
//==========================================================================
//
// CD_PlayCD
//
//==========================================================================
bool CD_PlayCD (bool looping)
{
if (Inited == NOT_INITED)
return false;
return CDThread->SendMessage (CDM_PlayCD, looping ? 1 : 0, 0, 0, true) == 0;
}
//==========================================================================
//
// CD_PlayCDNoWait
//
//==========================================================================
void CD_PlayCDNoWait (bool looping)
{
if (Inited != NOT_INITED)
CDThread->SendMessage (CDM_PlayCD, looping ? 1 : 0, 0, 0, false);
}
//==========================================================================
//
// ZMusic_CD_Pause
//
//==========================================================================
DLL_EXPORT void ZMusic_CD_Pause ()
{
if (Inited != NOT_INITED)
CDThread->SendMessage (CDM_Pause, 0, 0, 0, false);
}
//==========================================================================
//
// ZMusic_CD_Resume
//
//==========================================================================
DLL_EXPORT zmusic_bool ZMusic_CD_Resume ()
{
if (Inited == NOT_INITED)
return false;
return CDThread->SendMessage (CDM_Resume, 0, 0, 0, false) == 0;
}
//==========================================================================
//
// CD_GetMode
//
//==========================================================================
ECDModes CD_GetMode ()
{
if (Inited == NOT_INITED)
return CDMode_Unknown;
return (ECDModes)CDThread->SendMessage (CDM_GetMode, 0, 0, 0, true);
}
//==========================================================================
//
// CD_CheckTrack
//
//==========================================================================
bool CD_CheckTrack (int track)
{
if (Inited == NOT_INITED)
return false;
return CDThread->SendMessage (CDM_CheckTrack, track, 0, 0, true) != 0;
}
// Functions called only by the helper thread -------------------------------
//==========================================================================
//
// IsTrackAudio
//
//==========================================================================
bool FCDThread::IsTrackAudio (DWORD track) const
{
MCI_STATUS_PARMS statusParms;
statusParms.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
statusParms.dwTrack = track;
if (mciSendCommand (DeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK,
(DWORD_PTR)&statusParms))
{
return FALSE;
}
return statusParms.dwReturn == MCI_CDA_TRACK_AUDIO;
}
//==========================================================================
//
// GetTrackLength
//
//==========================================================================
DWORD FCDThread::GetTrackLength (DWORD track) const
{
MCI_STATUS_PARMS statusParms;
statusParms.dwItem = MCI_STATUS_LENGTH;
statusParms.dwTrack = track;
if (mciSendCommand (DeviceID, MCI_STATUS, MCI_STATUS_ITEM | MCI_TRACK,
(DWORD_PTR)&statusParms))
{
return 0;
}
else
{
return (DWORD)statusParms.dwReturn;
}
}
//==========================================================================
//
// GetNumTracks
//
//==========================================================================
DWORD FCDThread::GetNumTracks () const
{
MCI_STATUS_PARMS statusParms;
statusParms.dwItem = MCI_STATUS_NUMBER_OF_TRACKS;
if (mciSendCommand (DeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD_PTR)&statusParms))
{
return 0;
}
else
{
return (DWORD)statusParms.dwReturn;
}
}
//==========================================================================
//
// CD_WndProc (static)
//
// Because MCI (under Win 9x anyway) can't notify windows owned by another
// thread, the helper thread creates its own window.
//
//==========================================================================
LRESULT CALLBACK FCDThread::CD_WndProc (HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case MM_MCINOTIFY:
if (wParam == MCI_NOTIFY_SUCCESSFUL)
{
FCDThread *self = (FCDThread *)(LONG_PTR)GetWindowLongPtr (hWnd, GWLP_USERDATA);
// Using SendMessage could deadlock, so don't do that.
self->Dispatch (self->Looping ? CDM_Replay : CDM_Stop);
}
return 0;
default:
return DefWindowProc (hWnd, message, wParam, lParam);
}
}

View file

@ -1,72 +0,0 @@
/*
** i_cd.h
** Defines the CD interface
**
**---------------------------------------------------------------------------
** Copyright 1998-2006 Randy Heit
** All rights reserved.
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions
** are met:
**
** 1. Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** 2. Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in the
** documentation and/or other materials provided with the distribution.
** 3. The name of the author may not be used to endorse or promote products
** derived from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**---------------------------------------------------------------------------
**
*/
#ifndef __I_CD_H__
#define __I_CD_H__
enum ECDModes
{
CDMode_Unknown,
CDMode_NotReady,
CDMode_Pause,
CDMode_Play,
CDMode_Stop,
CDMode_Open
};
// Opens a CD device. If device is non-negative, it specifies which device
// to open. 0 is drive A:, 1 is drive B:, etc. If device is not specified,
// the user's preference is used to decide which device to open.
bool CD_Init (int device = -1);
// Open a CD device containing a specific CD. Tries device guess first.
bool CD_InitID (unsigned int id, int guess=-1);
// Plays a single track, possibly looping
bool CD_Play (int track, bool looping);
// Plays the first block of audio tracks on a CD, possibly looping
bool CD_PlayCD (bool looping);
// Versions of the above that return as soon as possible
void CD_PlayNoWait (int track, bool looping);
void CD_PlayCDNoWait (bool looping);
// Get the CD drive's status (mode)
ECDModes CD_GetMode ();
// Check if a track exists and is audio
bool CD_CheckTrack (int track);
#endif //__I_CD_H__

View file

@ -63,8 +63,6 @@ class MusInfo;
MusInfo *OpenStreamSong(StreamSource *source);
const char *GME_CheckFormat(uint32_t header);
MusInfo* CDDA_OpenSong(MusicIO::FileInterface* reader);
MusInfo* CD_OpenSong(int track, int id);
MusInfo* CreateMIDIStreamer(MIDISource *source, EZMusicMidiDevice devtype, const char* args);
//==========================================================================
@ -225,13 +223,6 @@ static MusInfo *ZMusic_OpenSongInternal (MusicIO::FileInterface *reader, EZMusi
info = CreateMIDIStreamer(source, device, Args? Args : "");
}
// Check for CDDA "format"
else if ((id[0] == MAKE_ID('R', 'I', 'F', 'F') && id[2] == MAKE_ID('C', 'D', 'D', 'A')))
{
// This is a CDDA file
info = CDDA_OpenSong(reader);
}
// Check for various raw OPL formats
else
{
@ -336,26 +327,6 @@ DLL_EXPORT ZMusic_MusicStream ZMusic_OpenSong(ZMusicCustomReader* reader, EZMusi
}
//==========================================================================
//
// play CD music
//
//==========================================================================
DLL_EXPORT MusInfo *ZMusic_OpenCDSong (int track, int id)
{
MusInfo *info = CD_OpenSong (track, id);
if (info && !info->IsValid ())
{
delete info;
info = nullptr;
SetError("Unable to open CD Audio");
}
return info;
}
//==========================================================================
//
// streaming callback