mirror of
https://github.com/ZDoom/ZMusic.git
synced 2025-03-13 06:02:24 +00:00
- removed Windows CD Audio support.
Better get rid of this legacy baggage now, before it is too later.
This commit is contained in:
parent
26f87a5055
commit
fb0abfcd08
8 changed files with 0 additions and 1465 deletions
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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 ();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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__
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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__
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue