diff options
Diffstat (limited to 'music')
-rw-r--r-- | music/bemidi.cpp | 51 | ||||
-rw-r--r-- | music/bemidi.h | 8 | ||||
-rw-r--r-- | music/dmusic.c | 112 | ||||
-rw-r--r-- | music/dmusic.h | 8 | ||||
-rw-r--r-- | music/dmusic2.cpp | 313 | ||||
-rw-r--r-- | music/extmidi.c | 112 | ||||
-rw-r--r-- | music/extmidi.h | 8 | ||||
-rw-r--r-- | music/null.c | 19 | ||||
-rw-r--r-- | music/null.h | 8 | ||||
-rw-r--r-- | music/win32.c | 146 | ||||
-rw-r--r-- | music/win32.h | 8 |
11 files changed, 793 insertions, 0 deletions
diff --git a/music/bemidi.cpp b/music/bemidi.cpp new file mode 100644 index 000000000..146df3031 --- /dev/null +++ b/music/bemidi.cpp @@ -0,0 +1,51 @@ +#include "stdafx.h" +#include "openttd.h" +#include "music/bemidi.h" + +// BeOS System Includes +#include <MidiSynthFile.h> + +BMidiSynthFile midiSynthFile; + +static const char *bemidi_start(const char * const *parm) +{ + return NULL; +} + +static void bemidi_stop(void) +{ + midiSynthFile.UnloadFile(); +} + +static void bemidi_play_song(const char *filename) +{ + bemidi_stop(); + entry_ref midiRef; + get_ref_for_path(filename, &midiRef); + midiSynthFile.LoadFile(&midiRef); + midiSynthFile.Start(); +} + +static void bemidi_stop_song(void) +{ + midiSynthFile.UnloadFile(); +} + +static bool bemidi_is_playing(void) +{ + return !midiSynthFile.IsFinished(); +} + +static void bemidi_set_volume(byte vol) +{ + fprintf(stderr, "BeMidi: Set volume not implemented\n"); +} + +const HalMusicDriver _bemidi_music_driver = { + bemidi_start, + bemidi_stop, + bemidi_play_song, + bemidi_stop_song, + bemidi_is_playing, + bemidi_set_volume, +}; diff --git a/music/bemidi.h b/music/bemidi.h new file mode 100644 index 000000000..049bf3247 --- /dev/null +++ b/music/bemidi.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_BEMIDI_H +#define MUSIC_BEMIDI_H + +#include "hal.h" + +extern const HalMusicDriver _bemidi_music_driver; + +#endif diff --git a/music/dmusic.c b/music/dmusic.c new file mode 100644 index 000000000..8842537a4 --- /dev/null +++ b/music/dmusic.c @@ -0,0 +1,112 @@ +/********************************************************************* + * OpenTTD: An Open Source Transport Tycoon Deluxe clone * + * Copyright (c) 2002-2004 OpenTTD Developers. All Rights Reserved. * + * * + * Web site: http://openttd.sourceforge.net/ * + *********************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* DirectMusic driver for Win32 */ +/* Based on dxmci from TTDPatch */ + +#include "stdafx.h" + +#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT + +#include "openttd.h" +#include "string.h" +#include "variables.h" +#include "sound.h" +#include "music/dmusic.h" + +static const char * DMusicMidiStart(const char * const *parm); +static void DMusicMidiStop(void); +static void DMusicMidiPlaySong(const char *filename); +static void DMusicMidiStopSong(void); +static bool DMusicMidiIsSongPlaying(void); +static void DMusicMidiSetVolume(byte vol); + +const HalMusicDriver _dmusic_midi_driver = { + DMusicMidiStart, + DMusicMidiStop, + DMusicMidiPlaySong, + DMusicMidiStopSong, + DMusicMidiIsSongPlaying, + DMusicMidiSetVolume, +}; + +extern bool LoadMIDI (char *directory, char *filename); +extern bool InitDirectMusic (void); +extern void ReleaseSegment (void); +extern void ShutdownDirectMusic (void); +extern bool LoadMIDI (char *directory, char *filename); +extern void PlaySegment (void); +extern void StopSegment (void); +extern bool IsSegmentPlaying (void); +extern void SetVolume (long); + +static bool seeking = false; + +static const char * DMusicMidiStart(const char * const *parm) +{ + return InitDirectMusic() ? NULL : "Unable to initialize DirectMusic"; +} + +static void DMusicMidiStop(void) +{ + StopSegment(); +} + +static void DMusicMidiPlaySong(const char *filename) +{ + char *pos; + char dir[MAX_PATH]; + char file[MAX_PATH]; + + // split full path into directory and file components + ttd_strlcpy(dir, filename, MAX_PATH); + pos = strrchr(dir, '\\') + 1; + ttd_strlcpy(file, pos, MAX_PATH); + *pos = '\0'; + + LoadMIDI(dir, file); + PlaySegment(); + seeking = true; +} + +static void DMusicMidiStopSong(void) +{ + StopSegment(); +} + +static bool DMusicMidiIsSongPlaying(void) +{ + /* Not the nicest code, but there is a short delay before playing actually + * starts. OpenTTD makes no provision for this. */ + if (!IsSegmentPlaying() && seeking) return true; + if (IsSegmentPlaying()) seeking = false; + + return IsSegmentPlaying(); +} + +static void DMusicMidiSetVolume(byte vol) +{ + SetVolume(vol); +} + +#endif /* WIN32_ENABLE_DIRECTMUSIC_SUPPORT */ diff --git a/music/dmusic.h b/music/dmusic.h new file mode 100644 index 000000000..dd05c2ced --- /dev/null +++ b/music/dmusic.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_DMUSIC_H +#define MUSIC_DMUSIC_H + +#include "hal.h" + +extern const HalMusicDriver _dmusic_midi_driver; + +#endif diff --git a/music/dmusic2.cpp b/music/dmusic2.cpp new file mode 100644 index 000000000..ee8f71008 --- /dev/null +++ b/music/dmusic2.cpp @@ -0,0 +1,313 @@ +/********************************************************************* + * OpenTTD: An Open Source Transport Tycoon Deluxe clone * + * Copyright (c) 2002-2004 OpenTTD Developers. All Rights Reserved. * + * * + * Web site: http://openttd.sourceforge.net/ * + *********************************************************************/ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* DirectMusic driver for Win32 */ +/* Based on dxmci from TTDPatch */ + +#include "stdafx.h" + +#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT + +// for gcc, the GUIDs are available in a library instead +#ifndef __GNUC__ +#define INITGUID +#endif + +#ifdef __cplusplus + extern "C" { +#endif + +#include "openttd.h" +#include "debug.h" +#include "sound.h" +#include "hal.h" + +#ifdef __cplusplus + } +#endif + +#include <windows.h> +#include <stdio.h> + +#include <dmksctrl.h> +#include <dmusici.h> +#include <dmusicc.h> +#include <dmusicf.h> + +#define MSGBOX(output) DEBUG(misc, 0) ("DirectMusic driver: %s\n", output); //MessageBox(NULL, output, "dxmci",MB_OK); + +static void MultiToWide(WCHAR* to, const char* from) +{ + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, from, -1, to, _MAX_PATH); +} + +// the performance object controls manipulation of the segments +static IDirectMusicPerformance *performance = NULL; + +// the segment object is where the MIDI data is stored for playback +static IDirectMusicSegment *segment = NULL; + +// the loader bject can load many types of DMusic related files +static IDirectMusicLoader *loader = NULL; + +// whether we've initialized COM or not (when deciding whether to shut down) +static int COMInitialized = 0; + + +extern "C" bool LoadLibraryList(void **proc, const char *dll); + +// Use lazy linking +struct ProcPtrs { + unsigned long (WINAPI *CoCreateInstance)(REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv); + HRESULT (WINAPI *CoInitialize)( LPVOID pvReserved ); + void (WINAPI *CoUninitialize)( ); +}; + +#define M(x) x "\0" +static const char ole_files[] = + M("ole32.dll") + M("CoCreateInstance") + M("CoInitialize") + M("CoUninitialize") + M("") +; +#undef M + + +static ProcPtrs _proc; + +static bool LoadOleDLL(void) +{ + if (_proc.CoCreateInstance != NULL) + return true; + if (!LoadLibraryList((void**)&_proc, ole_files)) + return false; + return true; +} + + +#ifdef __cplusplus +extern "C" { +#endif + +// Initialize COM and DirectMusic +bool InitDirectMusic(void) +{ + if (NULL != performance) + return true; + + // Initialize COM + if (!COMInitialized) { + if (!LoadOleDLL()) { + MSGBOX("ole32.dll load failed"); + return false; + } + + _proc.CoInitialize(NULL); + COMInitialized = 1; + } + + // Create the performance object via CoCreateInstance + if (FAILED(_proc.CoCreateInstance( + CLSID_DirectMusicPerformance, + NULL, + CLSCTX_INPROC, + IID_IDirectMusicPerformance, + (LPVOID*)&performance + ))) { + MSGBOX("Failed to create the performance object"); + return false; + } + + // Initialize it + if (FAILED(performance->Init(NULL, NULL, NULL))) { + MSGBOX("Failed to initialize performance object"); + return false; + } + + // Choose default Windows synth + if (FAILED(performance->AddPort(NULL))) { + MSGBOX("AddPort failed"); + return false; + } + + // now we'll create the loader object. This will be used to load the + // midi file for our demo. Again, we need to use CoCreateInstance + // and pass the appropriate ID parameters + if (FAILED(_proc.CoCreateInstance( + CLSID_DirectMusicLoader, + NULL, + CLSCTX_INPROC, + IID_IDirectMusicLoader, + (LPVOID*)&loader + ))) { + MSGBOX("Failed to create loader object"); + return false; + } + + // that's it for initialization. If we made it this far we + // were successful. + return true; +} + +// Releases memory used by all of the initialized +// DirectMusic objects in the program +void ReleaseSegment(void) +{ + if (NULL != segment) { + segment->Release(); + segment = NULL; + } +} + +void ShutdownDirectMusic(void) +{ + // release everything but the segment, which the performance + // will release automatically (and it'll crash if it's been + // released already) + + if (NULL != loader) { + loader->Release(); + loader = NULL; + } + + if (NULL != performance) { + performance->CloseDown(); + performance->Release(); + performance = NULL; + } + + if (COMInitialized) { + _proc.CoUninitialize(); + COMInitialized = 0; + } +} + +// Load MIDI file for playing +bool LoadMIDI(const char *directory, const char *filename) +{ + DMUS_OBJECTDESC obj_desc; + WCHAR w_directory[_MAX_PATH]; // utf-16 version of the directory name. + WCHAR w_filename[_MAX_PATH]; // utf-16 version of the file name + + if (NULL == performance) + return false; + + MultiToWide(w_directory, directory); + + if (FAILED(loader->SetSearchDirectory( + GUID_DirectMusicAllTypes, w_directory, FALSE + ))) { + MSGBOX("LoadMIDI: SetSearchDirectory failed"); + return false; + } + + // set up the loader object info + ZeroMemory(&obj_desc, sizeof(obj_desc)); + obj_desc.dwSize = sizeof(obj_desc); + + MultiToWide(w_filename, filename); + obj_desc.guidClass = CLSID_DirectMusicSegment; + + wcscpy(obj_desc.wszFileName, w_filename); + obj_desc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME; + + // release the existing segment if we have any + if (NULL != segment) + ReleaseSegment(); + + // and make a new segment + if (FAILED(loader->GetObject( + &obj_desc, IID_IDirectMusicSegment, (LPVOID*)&segment + ))) { + MSGBOX("LoadMIDI: Get object failed"); + return false; + } + + // next we need to tell the segment what kind of data it contains. We do this + // with the IDirectMusicSegment::SetParam function. + if (FAILED(segment->SetParam( + GUID_StandardMIDIFile, 0xFFFFFFFF, 0, 0, performance + ))) { + MSGBOX("LoadMIDI: SetParam (MIDI file) failed"); + return false; + } + + // finally, we need to tell the segment to 'download' the instruments + if (FAILED(segment->SetParam(GUID_Download, 0xFFFFFFFF, 0, 0, performance))) { + MSGBOX("LoadMIDI: Failed to download instruments"); + return false; + } + + // at this point, the MIDI file is loaded and ready to play! + return true; +} + +// Start playing the MIDI file +void PlaySegment(void) +{ + if (NULL == performance) + return; + + if (FAILED(performance->PlaySegment(segment, 0, 0, NULL))) { + MSGBOX("PlaySegment failed"); + } +} + +// Stop playing +void StopSegment(void) +{ + if (NULL == performance || NULL == segment) + return; + + if (FAILED(performance->Stop(segment, NULL, 0, 0))) { + MSGBOX("StopSegment failed"); + } +} + +// Find out whether playing has started or stopped +bool IsSegmentPlaying(void) +{ + if (NULL == performance || NULL == segment) + return false; + + // IsPlaying return S_OK if the segment is currently playing + return performance->IsPlaying(segment, NULL) == S_OK; +} + +void SetVolume(long vol) +{ + long db; + + if (performance == NULL && !InitDirectMusic()) + return; + + db = ((vol >> 21) & 0x7ff) - 1000; + performance->SetGlobalParam(GUID_PerfMasterVolume, &db, sizeof(db)); +} + +#if defined(__cplusplus) +} +#endif + +#endif /* WIN32_ENABLE_DIRECTMUSIC_SUPPORT */ diff --git a/music/extmidi.c b/music/extmidi.c new file mode 100644 index 000000000..031f7a383 --- /dev/null +++ b/music/extmidi.c @@ -0,0 +1,112 @@ +#ifndef __BEOS__ +#ifndef __MORPHOS__ +#include "stdafx.h" + +#include "openttd.h" +#include "music/extmidi.h" +#include "sound.h" +#include "string.h" +#include "variables.h" +#include <fcntl.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> +#include <signal.h> +#include <sys/stat.h> +#include <errno.h> + +static struct { + char song[MAX_PATH]; + int pid; +} _midi; + +static void DoPlay(void); +static void DoStop(void); + +static const char* ExtMidiStart(const char* const * parm) +{ + _midi.song[0] = '\0'; + _midi.pid = -1; + return NULL; +} + +static void ExtMidiStop(void) +{ + _midi.song[0] = '\0'; + DoStop(); +} + +static void ExtMidiPlaySong(const char* filename) +{ + ttd_strlcpy(_midi.song, filename, lengthof(_midi.song)); + DoStop(); +} + +static void ExtMidiStopSong(void) +{ + _midi.song[0] = '\0'; + DoStop(); +} + +static bool ExtMidiIsPlaying(void) +{ + if (_midi.pid != -1 && waitpid(_midi.pid, NULL, WNOHANG) == _midi.pid) + _midi.pid = -1; + if (_midi.pid == -1 && _midi.song[0] != '\0') DoPlay(); + return _midi.pid != -1; +} + +static void ExtMidiSetVolume(byte vol) +{ + fprintf(stderr, "extmidi: set volume not implemented\n"); +} + +static void DoPlay(void) +{ + _midi.pid = fork(); + switch (_midi.pid) { + case 0: { + int d; + + close(0); + close(1); + close(2); + d = open("/dev/null", O_RDONLY); + if (d != -1) { + if (dup2(d, 1) != -1 && dup2(d, 2) != -1) { + #if defined(MIDI_ARG) + execlp(msf.extmidi, "extmidi", MIDI_ARG, _midi.song, NULL); + #else + execlp(msf.extmidi, "extmidi", _midi.song, NULL); + #endif + } + } + exit(1); + } + + case -1: + fprintf(stderr, "extmidi: couldn't fork: %s\n", strerror(errno)); + /* FALLTHROUGH */ + + default: + _midi.song[0] = '\0'; + break; + } +} + +static void DoStop(void) +{ + if (_midi.pid != -1) kill(_midi.pid, SIGTERM); +} + +const HalMusicDriver _extmidi_music_driver = { + ExtMidiStart, + ExtMidiStop, + ExtMidiPlaySong, + ExtMidiStopSong, + ExtMidiIsPlaying, + ExtMidiSetVolume, +}; + +#endif /* __MORPHOS__ */ +#endif /* __BEOS__ */ diff --git a/music/extmidi.h b/music/extmidi.h new file mode 100644 index 000000000..3fb1848f7 --- /dev/null +++ b/music/extmidi.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_EXTERNAL_H +#define MUSIC_EXTERNAL_H + +#include "hal.h" + +extern const HalMusicDriver _extmidi_music_driver; + +#endif diff --git a/music/null.c b/music/null.c new file mode 100644 index 000000000..136f1d3e2 --- /dev/null +++ b/music/null.c @@ -0,0 +1,19 @@ +#include "stdafx.h" +#include "openttd.h" +#include "music/null.h" + +static const char* NullMidiStart(const char* const* parm) { return NULL; } +static void NullMidiStop(void) {} +static void NullMidiPlaySong(const char *filename) {} +static void NullMidiStopSong(void) {} +static bool NullMidiIsSongPlaying(void) { return true; } +static void NullMidiSetVolume(byte vol) {} + +const HalMusicDriver _null_music_driver = { + NullMidiStart, + NullMidiStop, + NullMidiPlaySong, + NullMidiStopSong, + NullMidiIsSongPlaying, + NullMidiSetVolume, +}; diff --git a/music/null.h b/music/null.h new file mode 100644 index 000000000..5f0be7ca4 --- /dev/null +++ b/music/null.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_NULL_H +#define MUSIC_NULL_H + +#include "hal.h" + +extern const HalMusicDriver _null_music_driver; + +#endif diff --git a/music/win32.c b/music/win32.c new file mode 100644 index 000000000..eb4d42d25 --- /dev/null +++ b/music/win32.c @@ -0,0 +1,146 @@ +#include "stdafx.h" +#include "openttd.h" +#include "music/win32.h" +#include <windows.h> + +static struct { + bool stop_song; + bool terminate; + bool playing; + int new_vol; + HANDLE wait_obj; + char start_song[260]; +} _midi; + +static void Win32MidiPlaySong(const char *filename) +{ + strcpy(_midi.start_song, filename); + _midi.playing = true; + _midi.stop_song = false; + SetEvent(_midi.wait_obj); +} + +static void Win32MidiStopSong(void) +{ + if (_midi.playing) { + _midi.stop_song = true; + _midi.start_song[0] = '\0'; + SetEvent(_midi.wait_obj); + } +} + +static bool Win32MidiIsSongPlaying(void) +{ + return _midi.playing; +} + +static void Win32MidiSetVolume(byte vol) +{ + _midi.new_vol = vol; + SetEvent(_midi.wait_obj); +} + +static long CDECL MidiSendCommand(const char *cmd, ...) { + va_list va; + char buf[512]; + + va_start(va, cmd); + vsprintf(buf, cmd, va); + va_end(va); + return mciSendStringA(buf, NULL, 0, 0); +} + +static bool MidiIntPlaySong(const char *filename) +{ + MidiSendCommand("close all"); + if (MidiSendCommand("open \"%s\" type sequencer alias song", filename) != 0) + return false; + + if (MidiSendCommand("play song from 0") != 0) + return false; + return true; +} + +static void MidiIntStopSong(void) +{ + MidiSendCommand("close all"); +} + +static void MidiIntSetVolume(int vol) +{ + uint v = (vol * 65535 / 127); + midiOutSetVolume((HMIDIOUT)-1, v + (v << 16)); +} + +static bool MidiIntIsSongPlaying(void) +{ + char buf[16]; + mciSendStringA("status song mode", buf, sizeof(buf), 0); + return strcmp(buf, "playing") == 0 || strcmp(buf, "seeking") == 0; +} + +static DWORD WINAPI MidiThread(LPVOID arg) +{ + _midi.wait_obj = CreateEvent(NULL, FALSE, FALSE, NULL); + + do { + char *s; + int vol; + + vol = _midi.new_vol; + if (vol != -1) { + _midi.new_vol = -1; + MidiIntSetVolume(vol); + } + + s = _midi.start_song; + if (s[0] != '\0') { + _midi.playing = MidiIntPlaySong(s); + s[0] = '\0'; + + // Delay somewhat in case we don't manage to play. + if (!_midi.playing) { + Sleep(5000); + } + } + + if (_midi.stop_song && _midi.playing) { + _midi.stop_song = false; + _midi.playing = false; + MidiIntStopSong(); + } + + if (_midi.playing && !MidiIntIsSongPlaying()) + _midi.playing = false; + + WaitForMultipleObjects(1, &_midi.wait_obj, FALSE, 1000); + } while (!_midi.terminate); + + DeleteObject(_midi.wait_obj); + return 0; +} + +static const char *Win32MidiStart(const char * const *parm) +{ + DWORD threadId; + + memset(&_midi, 0, sizeof(_midi)); + _midi.new_vol = -1; + CreateThread(NULL, 8192, MidiThread, 0, 0, &threadId); + return 0; +} + +static void Win32MidiStop(void) +{ + _midi.terminate = true; + SetEvent(_midi.wait_obj); +} + +const HalMusicDriver _win32_music_driver = { + Win32MidiStart, + Win32MidiStop, + Win32MidiPlaySong, + Win32MidiStopSong, + Win32MidiIsSongPlaying, + Win32MidiSetVolume, +}; diff --git a/music/win32.h b/music/win32.h new file mode 100644 index 000000000..8a2a0fb2d --- /dev/null +++ b/music/win32.h @@ -0,0 +1,8 @@ +#ifndef MUSIC_WIN32_H +#define MUSIC_WIN32_H + +#include "hal.h" + +extern const HalMusicDriver _win32_music_driver; + +#endif |