2017-04-17 10:27:19 +00:00
/*
* * music_midi_base . cpp
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 1998 - 2010 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 .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
2017-03-10 15:12:52 +00:00
# include "i_midi_win32.h"
2016-03-01 15:47:10 +00:00
# include "i_musicinterns.h"
# include "c_dispatch.h"
# include "i_music.h"
# include "i_system.h"
2017-04-18 12:42:08 +00:00
# include "gameconfigfile.h"
# include "cmdlib.h"
# include "m_misc.h"
2016-03-01 15:47:10 +00:00
# include "templates.h"
# include "v_text.h"
# include "menu/menu.h"
2017-03-10 18:46:22 +00:00
static uint32_t nummididevices ;
2016-03-01 15:47:10 +00:00
static bool nummididevicesset ;
# ifdef HAVE_FLUIDSYNTH
# define NUM_DEF_DEVICES 6
# else
# define NUM_DEF_DEVICES 5
# endif
2017-04-18 12:42:08 +00:00
//Provide some lists from which the user can choose the music resources in the menu instead of having to type them in manually
// These lists have to be maintained manually for the moment.
TArray < FString > SoundFonts ;
TArray < FString > PatchSets ;
TArray < FString > TimidityExes ;
static void ReadSoundFonts ( )
{
const char * key , * value ;
// Do not check for missing files here so that they will be saved back.
// Deletion should be done explicitly im the menu, equivalent to how the savegame menu works.
if ( GameConfig - > SetSection ( " SoundFonts " ) )
{
while ( GameConfig - > NextInSection ( key , value ) )
{
if ( FileExists ( value ) ) SoundFonts . Push ( value ) ;
}
}
if ( GameConfig - > SetSection ( " PatchSets " ) )
{
while ( GameConfig - > NextInSection ( key , value ) )
{
if ( FileExists ( value ) ) PatchSets . Push ( value ) ;
}
}
# ifdef _WIN32 // Different Timidity paths only make sense if they can be stored in arbitrary paths with local configs (i.e. not if things are done the Linux way)
if ( GameConfig - > SetSection ( " TimidityExes " ) )
{
while ( GameConfig - > NextInSection ( key , value ) )
{
if ( FileExists ( value ) ) PatchSets . Push ( value ) ;
}
}
# endif
}
2016-03-01 15:47:10 +00:00
static void AddDefaultMidiDevices ( FOptionValues * opt )
{
int p ;
FOptionValues : : Pair * pair = & opt - > mValues [ opt - > mValues . Reserve ( NUM_DEF_DEVICES ) ] ;
# ifdef HAVE_FLUIDSYNTH
pair [ 0 ] . Text = " FluidSynth " ;
pair [ 0 ] . Value = - 5.0 ;
p = 1 ;
# else
p = 0 ;
# endif
pair [ p ] . Text = " GUS " ;
pair [ p ] . Value = - 4.0 ;
pair [ p + 1 ] . Text = " OPL Synth Emulation " ;
pair [ p + 1 ] . Value = - 3.0 ;
pair [ p + 2 ] . Text = " TiMidity++ " ;
pair [ p + 2 ] . Value = - 2.0 ;
pair [ p + 3 ] . Text = " WildMidi " ;
pair [ p + 3 ] . Value = - 6.0 ;
pair [ p + 4 ] . Text = " Sound System " ;
pair [ p + 4 ] . Value = - 1.0 ;
}
2017-04-18 12:42:08 +00:00
void MIDIDeviceChanged ( int newdev , bool force )
2016-03-01 15:47:10 +00:00
{
static int oldmididev = INT_MIN ;
// If a song is playing, move it to the new device.
2017-04-18 12:42:08 +00:00
if ( oldmididev ! = newdev | | force )
2016-03-01 15:47:10 +00:00
{
if ( currSong ! = NULL & & currSong - > IsMIDI ( ) )
{
MusInfo * song = currSong ;
if ( song - > m_Status = = MusInfo : : STATE_Playing )
{
song - > Stop ( ) ;
song - > Start ( song - > m_Looping ) ;
}
}
else
{
S_MIDIDeviceChanged ( ) ;
}
}
2017-04-18 12:42:08 +00:00
// 'force'
if ( ! force ) oldmididev = newdev ;
2016-03-01 15:47:10 +00:00
}
# ifdef _WIN32
2017-03-10 15:12:52 +00:00
unsigned mididevice ;
2016-03-01 15:47:10 +00:00
CUSTOM_CVAR ( Int , snd_mididevice , - 1 , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
{
if ( ! nummididevicesset )
return ;
if ( ( self > = ( signed ) nummididevices ) | | ( self < - 6 ) )
{
2016-05-18 11:11:01 +00:00
// Don't do repeated message spam if there is no valid device.
if ( self ! = 0 )
{
Printf ( " ID out of range. Using default device. \n " ) ;
self = 0 ;
}
2016-03-01 15:47:10 +00:00
return ;
}
mididevice = MAX < UINT > ( 0 , self ) ;
MIDIDeviceChanged ( self ) ;
}
void I_InitMusicWin32 ( )
{
nummididevices = midiOutGetNumDevs ( ) ;
nummididevicesset = true ;
snd_mididevice . Callback ( ) ;
}
void I_BuildMIDIMenuList ( FOptionValues * opt )
{
AddDefaultMidiDevices ( opt ) ;
2017-03-10 18:46:22 +00:00
for ( uint32_t id = 0 ; id < nummididevices ; + + id )
2016-03-01 15:47:10 +00:00
{
MIDIOUTCAPS caps ;
MMRESULT res ;
res = midiOutGetDevCaps ( id , & caps , sizeof ( caps ) ) ;
assert ( res = = MMSYSERR_NOERROR ) ;
if ( res = = MMSYSERR_NOERROR )
{
FOptionValues : : Pair * pair = & opt - > mValues [ opt - > mValues . Reserve ( 1 ) ] ;
pair - > Text = caps . szPname ;
pair - > Value = ( float ) id ;
}
}
}
2017-03-10 18:46:22 +00:00
static void PrintMidiDevice ( int id , const char * name , uint16_t tech , uint32_t support )
2016-03-01 15:47:10 +00:00
{
if ( id = = snd_mididevice )
{
Printf ( TEXTCOLOR_BOLD ) ;
}
Printf ( " % 2d. %s : " , id , name ) ;
switch ( tech )
{
2017-03-10 11:39:23 +00:00
case MIDIDEV_MIDIPORT : Printf ( " MIDIPORT " ) ; break ;
case MIDIDEV_SYNTH : Printf ( " SYNTH " ) ; break ;
case MIDIDEV_SQSYNTH : Printf ( " SQSYNTH " ) ; break ;
case MIDIDEV_FMSYNTH : Printf ( " FMSYNTH " ) ; break ;
case MIDIDEV_MAPPER : Printf ( " MAPPER " ) ; break ;
case MIDIDEV_WAVETABLE : Printf ( " WAVETABLE " ) ; break ;
case MIDIDEV_SWSYNTH : Printf ( " SWSYNTH " ) ; break ;
2016-03-01 15:47:10 +00:00
}
if ( support & MIDICAPS_CACHE )
{
Printf ( " CACHE " ) ;
}
if ( support & MIDICAPS_LRVOLUME )
{
Printf ( " LRVOLUME " ) ;
}
if ( support & MIDICAPS_STREAM )
{
Printf ( " STREAM " ) ;
}
if ( support & MIDICAPS_VOLUME )
{
Printf ( " VOLUME " ) ;
}
Printf ( TEXTCOLOR_NORMAL " \n " ) ;
}
CCMD ( snd_listmididevices )
{
UINT id ;
MIDIOUTCAPS caps ;
MMRESULT res ;
2017-03-10 11:39:23 +00:00
PrintMidiDevice ( - 6 , " WildMidi " , MIDIDEV_SWSYNTH , 0 ) ;
2016-03-01 15:47:10 +00:00
# ifdef HAVE_FLUIDSYNTH
2017-03-10 11:39:23 +00:00
PrintMidiDevice ( - 5 , " FluidSynth " , MIDIDEV_SWSYNTH , 0 ) ;
2016-03-01 15:47:10 +00:00
# endif
2017-03-10 11:39:23 +00:00
PrintMidiDevice ( - 4 , " Gravis Ultrasound Emulation " , MIDIDEV_SWSYNTH , 0 ) ;
PrintMidiDevice ( - 3 , " Emulated OPL FM Synth " , MIDIDEV_FMSYNTH , 0 ) ;
PrintMidiDevice ( - 2 , " TiMidity++ " , MIDIDEV_SWSYNTH , 0 ) ;
2016-03-01 15:47:10 +00:00
PrintMidiDevice ( - 1 , " Sound System " , 0 , 0 ) ;
if ( nummididevices ! = 0 )
{
for ( id = 0 ; id < nummididevices ; + + id )
{
res = midiOutGetDevCaps ( id , & caps , sizeof ( caps ) ) ;
if ( res = = MMSYSERR_NODRIVER )
strcpy ( caps . szPname , " <Driver not installed> " ) ;
else if ( res = = MMSYSERR_NOMEM )
strcpy ( caps . szPname , " <No memory for description> " ) ;
else if ( res ! = MMSYSERR_NOERROR )
continue ;
PrintMidiDevice ( id , caps . szPname , caps . wTechnology , caps . dwSupport ) ;
}
}
}
# else
// Everything but Windows uses this code.
CUSTOM_CVAR ( Int , snd_mididevice , - 1 , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
{
if ( self < - 6 )
self = - 6 ;
else if ( self > - 1 )
self = - 1 ;
else
MIDIDeviceChanged ( self ) ;
}
void I_BuildMIDIMenuList ( FOptionValues * opt )
{
AddDefaultMidiDevices ( opt ) ;
}
CCMD ( snd_listmididevices )
{
Printf ( " %s-6. WildMidi \n " , - 6 = = snd_mididevice ? TEXTCOLOR_BOLD : " " ) ;
# ifdef HAVE_FLUIDSYNTH
Printf ( " %s-5. FluidSynth \n " , - 5 = = snd_mididevice ? TEXTCOLOR_BOLD : " " ) ;
# endif
Printf ( " %s-4. Gravis Ultrasound Emulation \n " , - 4 = = snd_mididevice ? TEXTCOLOR_BOLD : " " ) ;
Printf ( " %s-3. Emulated OPL FM Synth \n " , - 3 = = snd_mididevice ? TEXTCOLOR_BOLD : " " ) ;
Printf ( " %s-2. TiMidity++ \n " , - 2 = = snd_mididevice ? TEXTCOLOR_BOLD : " " ) ;
Printf ( " %s-1. Sound System \n " , - 1 = = snd_mididevice ? TEXTCOLOR_BOLD : " " ) ;
}
# endif