Browse Source

HL:Invasion Update Miniaudio implementation and remove GStreamer / FMod

invasion^2
Roy Shapiro 2 years ago
parent
commit
418ae2d41d
  1. 4
      CMakeLists.txt
  2. 27
      README.md
  3. 50
      dlls/CMakeLists.txt
  4. 1091
      dlls/fmod.h
  5. 32
      dlls/fmod_errors.h
  6. 462
      dlls/music.cpp
  7. 74
      dlls/music.h
  8. 446
      dlls/musicfmod.cpp
  9. 94
      dlls/musicfmod.h
  10. 511
      dlls/musicgstreamer.cpp
  11. 85
      dlls/musicgstreamer.h
  12. 495
      dlls/musicminiaudio.cpp
  13. 83
      dlls/musicminiaudio.h

4
CMakeLists.txt

@ -48,9 +48,7 @@ option(USE_VOICEMGR "Enable VOICE MANAGER." OFF) @@ -48,9 +48,7 @@ option(USE_VOICEMGR "Enable VOICE MANAGER." OFF)
option(BUILD_CLIENT "Build client dll" ON)
option(BUILD_SERVER "Build server dll" ON)
option(GOLDSOURCE_SUPPORT "Build goldsource compatible client library" OFF)
option(USE_GSTREAMER "Enable GStreamer." OFF)
option(USE_MINIAUDIO "Enable Miniaudio." OFF)
option(USE_FMOD "Enable FMOD." OFF)
option(DISABLE_MINIAUDIO "Disable Miniaudio." OFF)
if (CMAKE_SIZEOF_VOID_P EQUAL 4 OR
((WIN32 OR ${CMAKE_SYSTEM_NAME} STREQUAL "Linux")

27
README.md

@ -78,30 +78,15 @@ systems - you're more than welcome to do so! @@ -78,30 +78,15 @@ systems - you're more than welcome to do so!
mkdir build
cd build
cmake ../ -DUSE_VGUI=1 -DUSE_MINIAUDIO=1
cmake ../ -DUSE_VGUI=1
make
Must be built with -DUSE_VGUI=1 to work properly, as this mod makes heavy use of true-VGUI, thus update the modules when clonning.
Must be built with -DUSE_VGUI=1 to work properly, as this mod makes heavy use of true-VGUI,
also it builds with miniaudio by default, thus update the modules when clonning.
To be able to hear music during gameplay, on the following three is necessary:
-DUSE_MINIAUDIO=1 (this is the smallest and most compatible implementation as of now),
-DUSE_GSTREAMER=1 (and have appropriate architechture (i386) gstreamer-1.0 and dev packages installed), or,
-DUSE_FMOD=1 (untested, on Windows and will require fmod headers v 3.6.1 if you can still get them somewhere).
If using MiniAudio, make sure the submodules are updated.
As mentioned above, you have to do it anyway to get the VGUI headers.
If GStreamer is preferred, on Debian, the following is necessary to:
sudo apt install libgstreamer1.0:i386 #to play with music (also install plugins)
sudo apt install libgstreamer1.0-dev:i386 #to compile with music
So far GStreamer should only compile on Linux, as I haven't tested it (or linking it) on any other system.
Also, dlls/CMakeLists.txt must have a system-appropriate path to i386 version of GStreamer headers.
See set for ```ENV{PKG_CONFIG_PATH}```.
The FMod option can be used on Windows instead (uses windows.h include),
but requires and old and outdated FMod implementation v 3.6.1. Not recommended.
A miniaudio music player implementation is used to allow music during gameplay,
if it can not be used in your environment, it can be disabled with the use of:
-DDISABLE_MINIAUDIO=1 cmake option.
The following will likely be necessary to compile a gold-source compatible (old xash, e.t.c) binaries:

50
dlls/CMakeLists.txt

@ -37,16 +37,8 @@ else() @@ -37,16 +37,8 @@ else()
add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE)
endif()
if (USE_GSTREAMER AND (${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
add_definitions(-DUSE_GSTREAMER)
endif()
if (USE_MINIAUDIO)
add_definitions(-DUSE_MINIAUDIO)
endif()
if (USE_FMOD AND (WIN32 OR NOT (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")))
add_definitions(-DUSE_FMOD)
if (DISABLE_MINIAUDIO)
add_definitions(-DDISABLE_MINIAUDIO)
endif()
set (SVDLL_SOURCES
@ -170,40 +162,7 @@ set (SVDLL_SOURCES @@ -170,40 +162,7 @@ set (SVDLL_SOURCES
zombie.cpp
)
if (USE_GSTREAMER AND (${CMAKE_SYSTEM_NAME} STREQUAL "Linux"))
#if we're using gstreamer music
if (NOT 64BIT)
set(ENV{PKG_CONFIG_PATH} "/usr/lib/i386-linux-gnu/pkgconfig")
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(GLIB REQUIRED glib-2.0)
set(GSTREAMER_MINIMUM_VERSION 1.0.5)
pkg_check_modules(GST1_TEST gstreamer-1.0)
if ( GST1_TEST_FOUND AND NOT ${GST1_TEST_VERSION} VERSION_LESS ${GSTREAMER_MINIMUM_VERSION} )
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
add_definitions(-DGST_API_VERSION_1=1)
endif()
link_directories(
${GSTREAMER_LIBRARY_DIRS}
${GLIB_LIBRARY_DIRS}
)
set(GST_LIBRARIES
${GSTREAMER_LIBRARIES}
${GSTREAMER-APP_LIBRARIES}
${GSTREAMER-AUDIO_LIBRARIES}
${GSTREAMER-PBUTILS_LIBRARIES}
${GSTREAMER-FFT_LIBRARIES}
pthread
${GLIB_LIBRARIES}
${GLIB_GIO_LIBRARIES}
${GLIB_GOBJECT_LIBRARIES}
)
endif()
include_directories (. wpn_shared ../common ../engine ../pm_shared ../game_shared ../public ${GLIB_INCLUDE_DIRS} ${GSTREAMER_INCLUDE_DIRS})
include_directories (. wpn_shared ../common ../engine ../pm_shared ../game_shared ../public)
if(MSVC)
set(SVDLL_SOURCES
@ -220,9 +179,6 @@ else() @@ -220,9 +179,6 @@ else()
endif()
add_library (${SVDLL_LIBRARY} SHARED ${SVDLL_SOURCES})
if (USE_GSTREAMER AND (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")) #More gstreamer linkage stuff
target_link_libraries(${SVDLL_LIBRARY} ${GST_LIBRARIES})
endif()
set_target_properties (${SVDLL_LIBRARY} PROPERTIES
POSITION_INDEPENDENT_CODE 1)

1091
dlls/fmod.h

File diff suppressed because it is too large Load Diff

32
dlls/fmod_errors.h

@ -1,32 +0,0 @@ @@ -1,32 +0,0 @@
#ifndef _FMOD_ERRORS_H
#define _FMOD_ERRORS_H
static char *FMOD_ErrorString(int errcode)
{
switch (errcode)
{
case FMOD_ERR_NONE: return "No errors";
case FMOD_ERR_BUSY: return "Cannot call this command after FSOUND_Init. Call FSOUND_Close first.";
case FMOD_ERR_UNINITIALIZED: return "This command failed because FSOUND_Init was not called or called properly";
case FMOD_ERR_PLAY: return "Playing the sound failed.";
case FMOD_ERR_INIT: return "Error initializing output device.";
case FMOD_ERR_ALLOCATED: return "The output device is already in use and cannot be reused.";
case FMOD_ERR_OUTPUT_FORMAT: return "Soundcard does not support the features needed for this soundsystem (16bit stereo output)";
case FMOD_ERR_COOPERATIVELEVEL: return "Error setting cooperative level for hardware.";
case FMOD_ERR_CREATEBUFFER: return "Error creating hardware sound buffer.";
case FMOD_ERR_FILE_NOTFOUND: return "File not found";
case FMOD_ERR_FILE_FORMAT: return "Unknown file format";
case FMOD_ERR_FILE_BAD: return "Error loading file";
case FMOD_ERR_MEMORY: return "Not enough memory ";
case FMOD_ERR_VERSION: return "The version number of this file format is not supported";
case FMOD_ERR_INVALID_PARAM: return "An invalid parameter was passed to this function";
case FMOD_ERR_NO_EAX: return "Tried to use an EAX command on a non EAX enabled channel or output.";
case FMOD_ERR_CHANNEL_ALLOC: return "Failed to allocate a new channel";
case FMOD_ERR_RECORD: return "Recording not supported on this device";
case FMOD_ERR_MEDIAPLAYER: return "Required Mediaplayer codec is not installed";
default : return "Unknown error";
};
};
#endif

462
dlls/music.cpp

@ -1,28 +1,31 @@ @@ -1,28 +1,31 @@
//---------------------------------------------------------
//---------------------------------------------------------
//- ---
//- music.cpp ---
//- ---
//---------------------------------------------------------
//---------------------------------------------------------
//- by Roy, based on the code by JujU -----------
//---------------------------------------------------------
//- fake and null mp3 player code for HL mod -----------
//---------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-
//- music.cpp
//-
//-------------------------------------------------------------
//-------------------------------------------------------------
//- by Roy at suggestion by nekonomicon, based on code by JujU
//-------------------------------------------------------------
//- mp3 player code for HL mod
//-------------------------------------------------------------
//-
//- compatible with version 0.11.9 of Miniaudio
//- https://github.com/mackron/miniaudio
//-
//-------------------------------------------------------------
/*//---------------
/*
Don't forget to update the miniaudio submodule.
This code is a placeholder for systems that support neither gstreamer nor fmod.
Miniaudio 0.11.9 or better required.
Tested on Debian.
For playlist format see the bottom of the file.
*/
*///---------------
#ifdef USE_GSTREAMER
#include "musicgstreamer.cpp"
#elif defined(USE_MINIAUDIO)
#include "musicminiaudio.cpp"
#elif defined(USE_FMOD)
#include "musicfmod.cpp"
#else
//---------------------------------------------------------
// inclusions
@ -30,28 +33,342 @@ This code is a placeholder for systems that support neither gstreamer nor fmod. @@ -30,28 +33,342 @@ This code is a placeholder for systems that support neither gstreamer nor fmod.
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "gamerules.h" //We need g_pGameRules to determine if we're in multiplayer.
#include "music.h"
#ifndef DISABLE_MINIAUDIO //Use this to exclude the player in it's entirety. Will use empty "trigger_music" with no playback.
#include "music.h"
//These are just initial ones. If the actual track has different ones, they will be re-applied during Play().
#define SAMPLE_FORMAT ma_format_f32
#define CHANNEL_COUNT 2
#define SAMPLE_RATE 48000
CMusic g_MusicPlayer;
void CMusic_DecoderCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
//---------------------------------------------------------
// initialisation
void CMusic :: Init ( void )
{
if( m_bInit == TRUE ){
return; //Do not re-init.
}
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.format = SAMPLE_FORMAT;
deviceConfig.playback.channels = CHANNEL_COUNT;
deviceConfig.sampleRate = SAMPLE_RATE;
deviceConfig.dataCallback = CMusic_DecoderCallback; // this contains the callback that monitors the end of the song
deviceConfig.pUserData = NULL;
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {
ALERT ( at_console, "MUSICPLAYER : unable to initialize\n" );
return;
}
m_bInit = TRUE;
}
//---------------------------------------------------------
// Callback being called during playback
void CMusic_DecoderCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
if(g_MusicPlayer.m_IsPlaying == FALSE){
return; //We are paused or stopped, let's exit now.
}
ma_decoder* pDecoder = (ma_decoder*)&g_MusicPlayer.decoder;
if (pDecoder == NULL) {
return;
}
if(frameCount<=0) return;
ma_uint64 framesRead;
ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, &framesRead);
if(framesRead < frameCount) //This happens when the song ends.
g_MusicPlayer.songEnd();
(void)pInput;
}
//---------------------------------------------------------
// playing an audio file
void CMusic :: OpenFile ( const char *filename, int repeat )
{
audiofile_t *p = NULL;
p = new audiofile_t;
sprintf ( p->name, filename );
p->repeat = repeat;
p->next = m_pTrack;
m_pTrack = p;
}
//---------------------------------------------------------
// play a list of audio files
void CMusic :: OpenList ( const char *filename )
{
// open text file
FILE *myfile = fopen ( filename, "r" );
if ( myfile == NULL )
{
ALERT ( at_console, "MUSICPLAYER : impossible to load %s\n", filename );
return;
}
// saving songs to the list
int total = 0;
if ( fscanf ( myfile, "%i", &total ) != EOF )
{
for ( int i=0; i<total; i++ )
{
char ctitle [128];
int irepeat;
// reading the title
if ( fscanf ( myfile, "%s", ctitle ) != EOF )
{
if ( fscanf ( myfile, "%i", &irepeat ) != EOF )
OpenFile ( ctitle, irepeat );
else
break;
}
else
break;
}
}
// close text file
fclose ( myfile );
}
//---------------------------------------------------------
// end of the song
void CMusic :: songEnd ( )
{
// end of the song
g_MusicPlayer.Stop ();
// search for the first song in the list
audiofile_t *p = NULL;
p = g_MusicPlayer.m_pTrack;
while ( p != NULL )
{
if ( p->next == NULL )
break;
else
p = p->next;
}
if ( p == NULL )
{
ALERT ( at_console, "MUSICPLAYER : no song in the list\n" );
return;
}
// decrease repeat count
p->repeat --;
// removal of songs whose repeats ran off
if ( p->repeat < 1 )
{
if ( g_MusicPlayer.m_pTrack == p )
{
delete g_MusicPlayer.m_pTrack;
g_MusicPlayer.m_pTrack = NULL;
}
else
{
audiofile_t *q = NULL;
q = g_MusicPlayer.m_pTrack;
while ( q->next != p )
q = q->next;
delete q->next;
q->next = NULL;
}
}
// close player if list is empty
if ( g_MusicPlayer.m_pTrack == NULL )
{
g_MusicPlayer.Reset();
}
// next track start
else
{
g_MusicPlayer.Play();
}
return;
}
//Fake functions to have something to work with on Linux
//---------------------------------------------------------
// initiate playback
void CMusic :: Play ( void )
{
if ( m_IsPlaying == TRUE )
return;
if ( m_bInit == FALSE )
{
Init ();
if ( m_bInit == FALSE )
{
ALERT ( at_console, "MUSICPLAYER : unable to initialize\n" );
return;
}
}
// search for the first song in the list
audiofile_t *p = NULL;
p = m_pTrack;
while ( p != NULL )
{
if ( p->next == NULL )
break;
else
p = p->next;
}
if ( p == NULL )
{
ALERT ( at_console, "MUSICPLAYER : no song in the list\n" );
return;
}
//Stop playback
m_IsPlaying = FALSE; //Pause playback.
ma_decoder_seek_to_pcm_frame(&decoder, 0); //Reset the file to start.
// loading file
char payload [512];
sprintf(payload, "%s", p->name);
ALERT ( at_console, "MUSICPLAYER : Opening file %s.\n", payload );
result = ma_decoder_init_file(payload, NULL, &decoder);
if (result != MA_SUCCESS) {
ALERT ( at_console, "MUSICPLAYER : %s : can not load file\n", p->name );
return;
}
//If the new track has different properties to the previous one.
if(
deviceConfig.playback.format != decoder.outputFormat ||
deviceConfig.playback.channels != decoder.outputChannels ||
deviceConfig.sampleRate != decoder.outputSampleRate
){
deviceConfig.playback.format = decoder.outputFormat; //Change device settings
deviceConfig.playback.channels = decoder.outputChannels;
deviceConfig.sampleRate = decoder.outputSampleRate;
ALERT ( at_console, "MUSICPLAYER : Changing format to %d, channels to %d and sample rate to %d.\n", deviceConfig.playback.format, deviceConfig.playback.channels, deviceConfig.sampleRate);
//Now we need to recreate the device to apply.
ma_device_uninit(&device); //This is crucial, failing to do this results in segFault.
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) { //Apply new config.
ALERT ( at_console, "MUSICPLAYER : Failed to change playback device configuration.\n" );
g_MusicPlayer.m_bInit = FALSE; //We have been deinitialized. This is NOT ideal.
return;
}else
ALERT ( at_console, "MUSICPLAYER : New configuration applied successfully.\n");
}
void CMusic :: Init ( void ){}
void CMusic :: OpenFile ( const char *filename, int repeat ){}
void CMusic :: OpenList ( const char *filename ){}
signed char EndCallback ( void *stream, void *buff, int len, int param )
// playback
if (ma_device_start(&device) != MA_SUCCESS) {
ALERT ( at_console, "MUSICPLAYER : Failed to start playback device.\n" );
m_IsPlaying = FALSE; //Pause playback.
ma_decoder_seek_to_pcm_frame(&decoder, 0); //Reset the file to start.
return;
}else{
m_IsPlaying = TRUE;
}
return;
}
void CMusic :: Stop ( void )
{
return TRUE;
if ( m_IsPlaying == TRUE )
{
m_IsPlaying = FALSE; //Pause playback.
ma_decoder_seek_to_pcm_frame(&decoder, 0); //Reset the file to start.
}
}
void CMusic :: Play ( void ){}
void CMusic :: Stop ( void ){}
void CMusic :: Reset ( void ){}
void CMusic :: Reset ( void ) //Should instead be called "Next Track", but we keep Julien's naming.
{
//Reset the player.
if ( m_bInit == TRUE )
ALERT ( at_console, "MUSICPLAYER : Player reset.\n" );
Stop();
audiofile_t *p = NULL;
while ( m_pTrack != NULL )
{
p = m_pTrack;
m_pTrack = p->next;
delete p;
}
}
void CMusic :: Terminate ( void ) //Cleanup and dereference
{
ALERT ( at_console, "MUSICPLAYER : Terminating and unloading.\n" );
ma_device_uninit(&device);
ma_decoder_uninit(&decoder);
g_MusicPlayer.m_bInit = FALSE;
}
#endif //End if #ifndef DISABLE_MINIAUDIO
//---------------------------------------------------------
// The actual game entity
// entity class
@ -68,11 +385,12 @@ public: @@ -68,11 +385,12 @@ public:
virtual int Save ( CSave &save );
virtual int Restore ( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
string_t m_iFileName; // chemin du fichier
int m_iFileType; // fichier texte ( liste ) ou fichier audio
string_t m_iFileName; // file path
int m_iFileType; // text file (list) or audio file
};
@ -92,8 +410,14 @@ IMPLEMENT_SAVERESTORE( CTriggerMusic, CPointEntity ); @@ -92,8 +410,14 @@ IMPLEMENT_SAVERESTORE( CTriggerMusic, CPointEntity );
void CTriggerMusic :: Spawn( void )
{
if( g_pGameRules->IsDeathmatch() ) //Do not spawn in multiplayer.
{
REMOVE_ENTITY( ENT( pev ) );
return;
}
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
}
void CTriggerMusic :: KeyValue( KeyValueData *pkvd )
@ -114,6 +438,72 @@ void CTriggerMusic :: KeyValue( KeyValueData *pkvd ) @@ -114,6 +438,72 @@ void CTriggerMusic :: KeyValue( KeyValueData *pkvd )
void CTriggerMusic :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
return;
if( g_pGameRules->IsMultiplayer() ) //Do not activate / do anything in multiplayer.
return;
#ifndef DISABLE_MINIAUDIO
if ( g_MusicPlayer.m_IsPlaying == TRUE )
return;
if ( m_iFileType == MUSIC_AUDIO_FILE )
{
g_MusicPlayer.OpenFile ( STRING(m_iFileName), 1 );
}
else
{
g_MusicPlayer.OpenList ( STRING(m_iFileName) );
}
g_MusicPlayer.Play();
#else
return; //Do nothing, we have neither g_MusicPlayer, nor miniaudio.
#endif
}
#endif
/*
code
@PointClass base( Targetname ) = trigger_music : "Trigger Music"
[
filetype(choices) : "File type" : 0 =
[
0: "File list (*.txt)"
1: "File wav mp2 mp3 ogg raw"
]
filename(string) : "Name (mod/folder/file.extension)"
]
*/
/*//---------------
Playlist contents
example: music01.txt file:
//
3
monmod/sound/mp3/music01_debut.mp3 1
monmod/sound/mp3/music01_boucle.mp3 3
monmod/sound/mp3/music01_fin.mp3 1
//
composition :
- total number of tracks
- path of the first music file
- times to repeat that file
- path of the second
- etc ...
*///---------------

74
dlls/music.h

@ -1,20 +1,26 @@ @@ -1,20 +1,26 @@
//---------------------------------------------------------
//---------------------------------------------------------
//- ---
//- music.h ---
//- ---
//---------------------------------------------------------
//---------------------------------------------------------
//- by Roy, based on the code by JujU -----------
//---------------------------------------------------------
//- tee file for null player
//---------------------------------------------------------
//-------------------------------------------------------------
//-------------------------------------------------------------
//-
//- music.h
//-
//-------------------------------------------------------------
//-------------------------------------------------------------
//- by Roy at suggestion by nekonomicon, based on code by JujU
//-------------------------------------------------------------
//- mp3 player code for HL mod
//-------------------------------------------------------------
//-
//- compatible with version 0.11.9 of Miniaudio
//- https://github.com/mackron/miniaudio
//-
//-------------------------------------------------------------
#ifndef MUSIC_H
#define MUSIC_H
//Temporary plug to have something to work with on Linux modif de Roy
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio/miniaudio.h"
//---------------------------------------------------------
// defines
@ -22,7 +28,7 @@ @@ -22,7 +28,7 @@
#define MUSIC_LIST_FILE 0
//---------------------------------------------------------
// structure of the audio file entity
// audio file structure
struct audiofile_t
{
@ -32,41 +38,45 @@ struct audiofile_t @@ -32,41 +38,45 @@ struct audiofile_t
};
//---------------------------------------------------------
// music class
// reader class
class CMusic
{
public:
// fonctions de lecture
// reading functions
void OpenFile ( const char *filename, int repeat ); // ouverture d'un simple fichier
void OpenList ( const char *filename ); // ouverture d'un fichier texte contenant les fichiers
void OpenFile ( const char *filename, int repeat ); // open a single file
void OpenList ( const char *filename ); // opening a text file containing the files
void Init ( void ); // initialisation
void Init ( void ); // initialization
void Play ( void ); // lecture
void Stop ( void ); // arr
void Reset ( void ); // fermeture
void Play ( void ); // playback
void Stop ( void ); // stop
void Reset ( void ); // pause and switch to next track
void Terminate ( void ); // clean-up during termination
// variables
int m_fsound; //We don't actually have FMOD, so just an int handle.
BOOL m_IsPlaying; // t
BOOL m_bInit; // t
BOOL m_IsPlaying; // monitors whether the music is played, used to pause the music
BOOL m_bInit; // checks if the player is initialized
audiofile_t *m_pTrack; //current track
audiofile_t *m_pTrack; // playlist items
// constructor & destructor
// constructor / destructor
CMusic () { m_bInit = FALSE; m_IsPlaying = FALSE; m_pTrack = NULL; Reset(); };
~CMusic () {};
~CMusic () { Terminate(); };
// object instances
ma_result result;
ma_decoder decoder;
ma_device_config deviceConfig;
ma_device device;
// functions import
// none, see window / Julien's code.
void songEnd();
};
extern CMusic g_MusicPlayer;

446
dlls/musicfmod.cpp

@ -1,446 +0,0 @@ @@ -1,446 +0,0 @@
//---------------------------------------------------------
//---------------------------------------------------------
//- ---
//- musicfmod.cpp ---
//- ---
//---------------------------------------------------------
//---------------------------------------------------------
//- par JujU -----------
//- julien.lecorre@free.fr -----------
//---------------------------------------------------------
//- code du lecteur mp3 pour mod HL -----------
//---------------------------------------------------------
//- ---
//- compatible avec la version 3.6.1 de fmod.dll ---
//- http://www.fmod.org/ ---
//- ---
//---------------------------------------------------------
/*//---------------
mettre la dll fmod.dll dans le dossier half life.
changer l'adresse de la dll dans le #define FMOD_DLL_PATH
du fichier .h
attention, mettre des \\ et pas des \ dans l'adresse.
code
fin de ce fichier.
composition des fichiers texte listes de fichiers audio :
voir
*///---------------
//---------------------------------------------------------
// inclusions
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "musicfmod.h"
CMusic g_MusicPlayer;
//---------------------------------------------------------
// initialisation
void CMusic :: Init ( void )
{
m_hFmodDll = LoadLibrary ( FMOD_DLL_PATH );
if ( m_hFmodDll == NULL )
return;
(FARPROC&)FSOUND_INIT = GetProcAddress(m_hFmodDll, "_FSOUND_Init@12");
(FARPROC&)FSOUND_CLOSE = GetProcAddress(m_hFmodDll, "_FSOUND_Close@0");
(FARPROC&)FSOUND_STREAM_OPENFILE = GetProcAddress(m_hFmodDll, "_FSOUND_Stream_OpenFile@12");
(FARPROC&)FSOUND_STREAM_CLOSE = GetProcAddress(m_hFmodDll, "_FSOUND_Stream_Close@4");
(FARPROC&)FSOUND_STREAM_PLAY = GetProcAddress(m_hFmodDll, "_FSOUND_Stream_Play@8");
(FARPROC&)FSOUND_STREAM_ENDCALLBACK = GetProcAddress(m_hFmodDll, "_FSOUND_Stream_SetEndCallback@12");
if ( !( FSOUND_INIT && FSOUND_CLOSE && FSOUND_STREAM_OPENFILE && FSOUND_STREAM_CLOSE && FSOUND_STREAM_PLAY && FSOUND_STREAM_ENDCALLBACK ))
{
FreeLibrary( m_hFmodDll );
return;
}
if (!FSOUND_INIT(44100, 1, 0))
return;
m_bInit = TRUE;
}
//---------------------------------------------------------
// lecture d'un fichier audio
void CMusic :: OpenFile ( const char *filename, int repeat )
{
audiofile_t *p = NULL;
p = new audiofile_t;
sprintf ( p->name, filename );
p->repeat = repeat;
p->next = m_pTrack;
m_pTrack = p;
}
//---------------------------------------------------------
// lecture d'une liste de fichiers audio
void CMusic :: OpenList ( const char *filename )
{
// ouverture du fichier texte
FILE *myfile = fopen ( filename, "r" );
if ( myfile == NULL )
{
ALERT ( at_console, "\\\nMUSICPLAYER : impossible d'ouvrir %s\n\\\n", filename );
return;
}
// enregistrement des morceaux dans la liste
int total = 0;
if ( fscanf ( myfile, "%i", &total ) != EOF )
{
for ( int i=0; i<total; i++ )
{
char ctitle [128];
int irepeat;
// lecture du titre
if ( fscanf ( myfile, "%s", ctitle ) != EOF )
{
if ( fscanf ( myfile, "%i", &irepeat ) != EOF )
OpenFile ( ctitle, irepeat );
else
break;
}
else
break;
}
}
// fermeture du fichier texte
fclose ( myfile );
}
//---------------------------------------------------------
// fin du morceau
signed char EndCallback ( FSOUND_STREAM *stream, void *buff, int len, int param )
{
// fin du morceau
g_MusicPlayer.Stop ();
// recherche du premier morceau de la liste
audiofile_t *p = NULL;
p = g_MusicPlayer.m_pTrack;
while ( p != NULL )
{
if ( p->next == NULL )
break;
else
p = p->next;
}
if ( p == NULL )
{
ALERT ( at_console, "\\\nMUSICPLAYER : aucun morceau dans la liste\n\\\n" );
return TRUE;
}
// d
p->repeat --;
// suppression des morceaux dont la r
if ( p->repeat < 1 )
{
if ( g_MusicPlayer.m_pTrack == p )
{
delete g_MusicPlayer.m_pTrack;
g_MusicPlayer.m_pTrack = NULL;
}
else
{
audiofile_t *q = NULL;
q = g_MusicPlayer.m_pTrack;
while ( q->next != p )
q = q->next;
delete q->next;
q->next = NULL;
}
}
// fermeture du lecteur si la liste est vide
if ( g_MusicPlayer.m_pTrack == NULL )
{
g_MusicPlayer.Reset ();
}
// lancement du morceau suivant
else
{
g_MusicPlayer.Play();
}
return TRUE;
}
//---------------------------------------------------------
// lecture
void CMusic :: Play ( void )
{
if ( m_IsPlaying == TRUE )
return;
if ( m_bInit == FALSE )
{
Init ();
if ( m_bInit == FALSE )
{
ALERT ( at_console, "\\\nMUSICPLAYER : initialisation impossible\n\\\n" );
return;
}
}
// recherche du premier morceau de la liste
audiofile_t *p = NULL;
p = m_pTrack;
while ( p != NULL )
{
if ( p->next == NULL )
break;
else
p = p->next;
}
if ( p == NULL )
{
ALERT ( at_console, "\\\nMUSICPLAYER : aucun morceau dans la liste\n\\\n" );
return;
}
// chargement du fichier
m_fsound = FSOUND_STREAM_OPENFILE( p->name, FSOUND_NORMAL | FSOUND_LOOP_OFF, 0 );
if (!m_fsound)
{
ALERT ( at_console, "\\\nMUSICPLAYER : %s : fichier introuvable\n\\\n", p->name );
return;
}
// lecture
FSOUND_STREAM_PLAY ( FSOUND_FREE, m_fsound );
m_IsPlaying = TRUE;
// callback en fin de morceau
FSOUND_STREAM_ENDCALLBACK ( m_fsound, EndCallback, 0 );
}
void CMusic :: Stop ( void )
{
if ( m_IsPlaying == TRUE )
{
m_IsPlaying = FALSE;
FSOUND_STREAM_CLOSE ( m_fsound );
}
}
void CMusic :: Reset ( void )
{
//r
Stop ();
audiofile_t *p = NULL;
while ( m_pTrack != NULL )
{
p = m_pTrack;
m_pTrack = p->next;
delete p;
}
if ( m_bInit == TRUE )
{
FSOUND_CLOSE();
g_MusicPlayer.m_bInit = FALSE;
// FreeLibrary( g_MusicPlayer.m_hFmodDll );
g_MusicPlayer.m_hFmodDll = NULL;
}
}
//---------------------------------------------------------
// classe de l'entit
class CTriggerMusic : public CPointEntity
{
public:
void Spawn ( void );
void KeyValue ( KeyValueData *pkvd );
void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int Save ( CSave &save );
virtual int Restore ( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
string_t m_iFileName; // chemin du fichier
int m_iFileType; // fichier texte ( liste ) ou fichier audio
};
LINK_ENTITY_TO_CLASS( trigger_music, CTriggerMusic );
TYPEDESCRIPTION CTriggerMusic::m_SaveData[] =
{
DEFINE_FIELD( CTriggerMusic, m_iFileType, FIELD_INTEGER ),
DEFINE_FIELD( CTriggerMusic, m_iFileName, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CTriggerMusic, CPointEntity );
void CTriggerMusic :: Spawn( void )
{
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
}
void CTriggerMusic :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "filetype"))
{
m_iFileType = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "filename"))
{
m_iFileName = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CPointEntity::KeyValue( pkvd );
}
void CTriggerMusic :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( g_MusicPlayer.m_IsPlaying == TRUE )
return;
if ( m_iFileType == MUSIC_AUDIO_FILE )
{
g_MusicPlayer.OpenFile ( STRING(m_iFileName), 1 );
}
else
{
g_MusicPlayer.OpenList ( STRING(m_iFileName) );
}
g_MusicPlayer.Play();
}
/*//---------------
code
@PointClass base( Targetname ) = trigger_music : "Trigger Music"
[
filetype(choices) : "Type de fichier" : 0 =
[
0: "Liste de fichiers (*.txt)"
1: "Fichier wav mp2 mp3 ogg raw"
]
filename(string) : "Nom (mod/dossier/fichier.extension)"
]
*///---------------
/*//---------------
composition des listes de fichiers audio
exemple : fichier music01.txt :
//
3
monmod/sound/mp3/music01_debut.mp3 1
monmod/sound/mp3/music01_boucle.mp3 3
monmod/sound/mp3/music01_fin.mp3 1
//
composition :
- nombre total de morceaux diff
- adresse du premier fichier musique
- nombre de lectures de ce fichier
- adresse du deuxi
- etc ...
*///---------------

94
dlls/musicfmod.h

@ -1,94 +0,0 @@ @@ -1,94 +0,0 @@
//---------------------------------------------------------
//---------------------------------------------------------
//- ---
//- musicfmod.h ---
//- ---
//---------------------------------------------------------
//---------------------------------------------------------
//- par JujU -----------
//- julien.lecorre@free.fr -----------
//---------------------------------------------------------
//- fichier d'en t
//---------------------------------------------------------
//- ---
//- compatible avec la version 3.6.1 de fmod.dll ---
//- http://www.fmod.org/ ---
//- ---
//---------------------------------------------------------
#ifndef MUSIC_H
#define MUSIC_H
#include <fmod.h>
#include <windows.h>
//---------------------------------------------------------
// defines
#define MUSIC_AUDIO_FILE 1
#define MUSIC_LIST_FILE 0
#define FMOD_DLL_PATH "invasion\\fmod.dll"
//---------------------------------------------------------
// structure fichier audio
struct audiofile_t
{
char name [128];
int repeat;
audiofile_t *next;
};
//---------------------------------------------------------
// classe du lecteur
class CMusic
{
public:
// fonctions de lecture
void OpenFile ( const char *filename, int repeat ); // ouverture d'un simple fichier
void OpenList ( const char *filename ); // ouverture d'un fichier texte contenant les fichiers
void Init ( void ); // initialisation
void Play ( void ); // lecture
void Stop ( void ); // arr
void Reset ( void ); // fermeture
// variables
FSOUND_STREAM *m_fsound; // handle du fichier en cours de lecture
BOOL m_IsPlaying; // t
BOOL m_bInit; // t
audiofile_t *m_pTrack; // morceaux
// constructeur / destructeur
CMusic () { m_bInit = FALSE; m_IsPlaying = FALSE; m_pTrack = NULL; Reset(); };
~CMusic () {};
// fonctions import
signed char (_stdcall * FSOUND_INIT ) (int mixrate, int maxsoftwarechannels, unsigned int flags);
void (_stdcall * FSOUND_CLOSE ) (void);
FSOUND_STREAM * (_stdcall * FSOUND_STREAM_OPENFILE ) (const char *filename, unsigned int mode, int memlength);
signed char (_stdcall * FSOUND_STREAM_CLOSE ) (FSOUND_STREAM *stream);
int (_stdcall * FSOUND_STREAM_PLAY ) (int channel, FSOUND_STREAM *stream);
signed char (_stdcall * FSOUND_STREAM_ENDCALLBACK) (FSOUND_STREAM *stream, FSOUND_STREAMCALLBACK callback, int userdata);
HINSTANCE m_hFmodDll;
};
extern CMusic g_MusicPlayer;
#endif // MUSIC_H

511
dlls/musicgstreamer.cpp

@ -1,511 +0,0 @@ @@ -1,511 +0,0 @@
//---------------------------------------------------------
//---------------------------------------------------------
//- ---
//- musicgstreamer.cpp ---
//- ---
//---------------------------------------------------------
//---------------------------------------------------------
//- by Roy, based on the code by JujU -----------
//---------------------------------------------------------
//- mp3 player code for HL mod -----------
//---------------------------------------------------------
//- ---
//- compatible with version 1.0 of Gstreamer ---
//- http://www.gstreamer.freedesktop.org/ ---
//- ---
//---------------------------------------------------------
/*//---------------
Don't forget to link the actual library to GStreamer.
GStreamer 1.0 or better required.
Tested
with 32-bit GStreamer on Debian
For playlist format:
see the bottom of the file
*///---------------
//---------------------------------------------------------
// inclusions
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "musicgstreamer.h"
CMusic g_MusicPlayer;
//---------------------------------------------------------
// initialisation
void CMusic :: Init ( void )
{
int argc = 0;
char** argv = nullptr;
GError *error = nullptr;
if( m_bInit == TRUE ){
return; //Do not re-init.
}
if (gst_init_check(&argc,&argv,&error)!=TRUE)
{
ALERT ( at_console, "\\\nMUSICPLAYER : unable to initialize\n\\\n" );
return;
}
m_bInit = TRUE;
}
//---------------------------------------------------------
// monitoring the bus
void CMusic :: updateBus ( )
{
if(gstBus == NULL) return; //Do not react if bus doesn't exist.
gstMsg = gst_bus_pop (gstBus);
if(gstMsg != NULL){
if (GST_MESSAGE_TYPE (gstMsg) == GST_MESSAGE_ERROR) {
ALERT( at_console, "\\\nMUSICPLAYER : A GStreamer error has occured.\n\\\n" );
}else if (GST_MESSAGE_TYPE (gstMsg) == GST_MESSAGE_EOS) {
ALERT( at_console, "\\\nMUSICPLAYER : A song has ended.\n\\\n" );
songEnd();
}
}
if(gstMsg != NULL) gst_message_unref (gstMsg);
}
//---------------------------------------------------------
// playing an audio file
void CMusic :: OpenFile ( const char *filename, int repeat )
{
audiofile_t *p = NULL;
p = new audiofile_t;
sprintf ( p->name, filename );
p->repeat = repeat;
p->next = m_pTrack;
m_pTrack = p;
}
//---------------------------------------------------------
// play a list of audio files
void CMusic :: OpenList ( const char *filename )
{
// open text file
FILE *myfile = fopen ( filename, "r" );
if ( myfile == NULL )
{
ALERT ( at_console, "\\\nMUSICPLAYER : impossible to load %s\n\\\n", filename );
return;
}
// saving songs to the list
int total = 0;
if ( fscanf ( myfile, "%i", &total ) != EOF )
{
for ( int i=0; i<total; i++ )
{
char ctitle [128];
int irepeat;
// reading the title
if ( fscanf ( myfile, "%s", ctitle ) != EOF )
{
if ( fscanf ( myfile, "%i", &irepeat ) != EOF )
OpenFile ( ctitle, irepeat );
else
break;
}
else
break;
}
}
// close text file
fclose ( myfile );
}
//---------------------------------------------------------
// end of the song
void CMusic :: songEnd ( )
{
// end of the song
g_MusicPlayer.Stop ();
// search for the first song in the list
audiofile_t *p = NULL;
p = g_MusicPlayer.m_pTrack;
while ( p != NULL )
{
if ( p->next == NULL )
break;
else
p = p->next;
}
if ( p == NULL )
{
ALERT ( at_console, "\\\nMUSICPLAYER : no song in the list\n\\\n" );
return;
}
// d
p->repeat --;
// removal of songs whose r
if ( p->repeat < 1 )
{
if ( g_MusicPlayer.m_pTrack == p )
{
delete g_MusicPlayer.m_pTrack;
g_MusicPlayer.m_pTrack = NULL;
}
else
{
audiofile_t *q = NULL;
q = g_MusicPlayer.m_pTrack;
while ( q->next != p )
q = q->next;
delete q->next;
q->next = NULL;
}
}
// close player if list is empty
if ( g_MusicPlayer.m_pTrack == NULL )
{
g_MusicPlayer.Reset ();
}
// next track start
else
{
g_MusicPlayer.Play();
}
return;
}
//---------------------------------------------------------
// instruction
void CMusic :: Play ( void )
{
if ( m_IsPlaying == TRUE )
return;
if ( m_bInit == FALSE )
{
Init ();
if ( m_bInit == FALSE )
{
ALERT ( at_console, "\\\nMUSICPLAYER : unable to initialize\n\\\n" );
return;
}
}
// search for the first song in the list
audiofile_t *p = NULL;
p = m_pTrack;
while ( p != NULL )
{
if ( p->next == NULL )
break;
else
p = p->next;
}
if ( p == NULL )
{
ALERT ( at_console, "\\\nMUSICPLAYER : no song in the list\n\\\n" );
return;
}
//Stop previous pipeline activity
if (gstPipeline != NULL){
gst_element_set_state (gstPipeline, GST_STATE_NULL);
gst_object_unref (gstPipeline);
gstPipeline = NULL;
}
if (gstBus != NULL){
gst_object_unref (gstBus);
gstBus = NULL;
}
// loading file
char pipelinePayload [512];
sprintf(pipelinePayload, "filesrc location=%s ! decodebin ! audioconvert ! audioresample ! autoaudiosink", p->name);
gstPipeline = gst_parse_launch(pipelinePayload, NULL);
if (gstPipeline == NULL)
{
ALERT ( at_console, "\\\nMUSICPLAYER : %s : can not start playing the file\n\\\n", p->name );
return;
}
// playback
gst_element_set_state (gstPipeline, GST_STATE_PLAYING);
m_IsPlaying = TRUE;
// callback at the end of the song
gstBus = gst_element_get_bus (gstPipeline); //Get bus to monitor
}
void CMusic :: Stop ( void )
{
if ( m_IsPlaying == TRUE )
{
m_IsPlaying = FALSE;
if (gstPipeline != NULL){
gst_element_set_state (gstPipeline, GST_STATE_READY);
}
}
}
void CMusic :: Reset ( void )
{
//r
Stop ();
audiofile_t *p = NULL;
while ( m_pTrack != NULL )
{
p = m_pTrack;
m_pTrack = p->next;
delete p;
}
if ( m_bInit == TRUE )
{
if (gstPipeline != NULL){
gst_element_set_state (gstPipeline, GST_STATE_NULL);
gst_object_unref (gstPipeline);
gstPipeline = NULL;
}
if (gstBus != NULL){
gst_object_unref (gstBus);
gstBus = NULL;
}
//complete
//we don't actually de-initialize gst here
}
}
void CMusic :: Terminate ( void ) //Cleanup and dereference
{
Stop ();
if ( m_bInit == TRUE )
{
ALERT ( at_console, "\\\nMUSICPLAYER : de-initializing and dereferencing\n\\\n" );
if (gstPipeline != NULL){
gst_element_set_state (gstPipeline, GST_STATE_NULL);
gst_object_unref (gstPipeline);
gstPipeline = NULL;
}
if (gstBus != NULL){
gst_object_unref (gstBus);
gstBus = NULL;
}
gst_deinit ();
g_MusicPlayer.m_bInit = FALSE; //Neither.
//complete
}
}
//---------------------------------------------------------
// entity class
class CTriggerMusic : public CPointEntity
{
public:
void Spawn ( void );
void KeyValue ( KeyValueData *pkvd );
void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
void EXPORT Think( void );
virtual int Save ( CSave &save );
virtual int Restore ( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
string_t m_iFileName; // file path
int m_iFileType; // text file (list) or audio file
};
LINK_ENTITY_TO_CLASS( trigger_music, CTriggerMusic );
TYPEDESCRIPTION CTriggerMusic::m_SaveData[] =
{
DEFINE_FIELD( CTriggerMusic, m_iFileType, FIELD_INTEGER ),
DEFINE_FIELD( CTriggerMusic, m_iFileName, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CTriggerMusic, CPointEntity );
void CTriggerMusic :: Spawn( void )
{
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
SetThink( &CTriggerMusic::Think );
pev->nextthink = gpGlobals->time;
}
void CTriggerMusic::Think( void ) //We need to monitor gst message bus for updates
{
//if(g_MusicPlayer == NULL) return;
g_MusicPlayer.updateBus();
pev->nextthink = gpGlobals->time + 0.25f; // Think again in 1/4 second
}
void CTriggerMusic :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "filetype"))
{
m_iFileType = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "filename"))
{
m_iFileName = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CPointEntity::KeyValue( pkvd );
}
void CTriggerMusic :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( g_MusicPlayer.m_IsPlaying == TRUE )
return;
if ( m_iFileType == MUSIC_AUDIO_FILE )
{
g_MusicPlayer.OpenFile ( STRING(m_iFileName), 1 );
}
else
{
g_MusicPlayer.OpenList ( STRING(m_iFileName) );
}
g_MusicPlayer.Play();
}
/*//---------------
code
@PointClass base( Targetname ) = trigger_music : "Trigger Music"
[
filetype(choices) : "File type" : 0 =
[
0: "File list (*.txt)"
1: "File wav mp2 mp3 ogg raw"
]
filename(string) : "Name (mod/folder/file.extension)"
]
*///---------------
/*//---------------
composing lists of audio files
example: music01.txt file:
//
3
monmod/sound/mp3/music01_debut.mp3 1
monmod/sound/mp3/music01_boucle.mp3 3
monmod/sound/mp3/music01_fin.mp3 1
//
composition :
- total number of diff chunks
- address of the first music file
- number of readings of this file
- address of the second
- etc ...
*///---------------

85
dlls/musicgstreamer.h

@ -1,85 +0,0 @@ @@ -1,85 +0,0 @@
//---------------------------------------------------------
//---------------------------------------------------------
//- ---
//- musicgstreamer.h ---
//- ---
//---------------------------------------------------------
//---------------------------------------------------------
//- by Roy, based on the code by JujU -----------
//---------------------------------------------------------
//- tee file
//---------------------------------------------------------
//- ---
//- compatible with version 1.0 of Gstreamer ---
//- http://www.gstreamer.freedesktop.org/ ---
//- ---
//---------------------------------------------------------
#ifndef MUSIC_H
#define MUSIC_H
#include <gst/gst.h>
//---------------------------------------------------------
// defines
#define MUSIC_AUDIO_FILE 1
#define MUSIC_LIST_FILE 0
//---------------------------------------------------------
// audio file structure
struct audiofile_t
{
char name [128];
int repeat;
audiofile_t *next;
};
//---------------------------------------------------------
// reader class
class CMusic
{
public:
// reading functions
void OpenFile ( const char *filename, int repeat ); // open a single file
void OpenList ( const char *filename ); // opening a text file containing the files
void Init ( void ); // initialization
void Play ( void ); // playback
void Stop ( void ); // stop
void Reset ( void ); // closing, but not really
void Terminate ( void ); // actually closing
// variables
BOOL m_IsPlaying; // t
BOOL m_bInit; // t
audiofile_t *m_pTrack; // parts
// constructor / destructor
CMusic () { m_bInit = FALSE; m_IsPlaying = FALSE; m_pTrack = NULL; Reset(); };
~CMusic () { Terminate(); };
// import functions
GstElement *gstPipeline;
GstBus *gstBus;
GstMessage *gstMsg;
void updateBus();
void songEnd();
};
extern CMusic g_MusicPlayer;
#endif // MUSIC_H

495
dlls/musicminiaudio.cpp

@ -1,495 +0,0 @@ @@ -1,495 +0,0 @@
//-------------------------------------------------------------
//-------------------------------------------------------------
//-
//- musicminiaudio.cpp
//-
//-------------------------------------------------------------
//-------------------------------------------------------------
//- by Roy at suggestion by nekonomicon, based on code by JujU
//-------------------------------------------------------------
//- mp3 player code for HL mod
//-------------------------------------------------------------
//-
//- compatible with version 0.11.9 of Miniaudio
//- https://github.com/mackron/miniaudio
//-
//-------------------------------------------------------------
/*
Don't forget to update the miniaudio submodule.
Miniaudio 0.11.9 or better required.
Tested on Debian.
For playlist format see the bottom of the file.
*/
//---------------------------------------------------------
// inclusions
#include "extdll.h"
#include "util.h"
#include "cbase.h"
#include "musicminiaudio.h"
//These are just initial ones. If the actual track has different ones, they will be re-applied during Play().
#define SAMPLE_FORMAT ma_format_f32
#define CHANNEL_COUNT 2
#define SAMPLE_RATE 48000
CMusic g_MusicPlayer;
void CMusic_DecoderCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount);
//---------------------------------------------------------
// initialisation
void CMusic :: Init ( void )
{
if( m_bInit == TRUE ){
return; //Do not re-init.
}
deviceConfig = ma_device_config_init(ma_device_type_playback);
deviceConfig.playback.format = SAMPLE_FORMAT;
deviceConfig.playback.channels = CHANNEL_COUNT;
deviceConfig.sampleRate = SAMPLE_RATE;
deviceConfig.dataCallback = CMusic_DecoderCallback; // this contains the callback that monitors the end of the song
deviceConfig.pUserData = NULL;
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) {
ALERT ( at_console, "MUSICPLAYER : unable to initialize\n" );
return;
}
m_bInit = TRUE;
}
//---------------------------------------------------------
// Callback being called during playback
void CMusic_DecoderCallback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
if(g_MusicPlayer.m_IsPlaying == FALSE){
return; //We are paused or stopped, let's exit now.
}
ma_decoder* pDecoder = (ma_decoder*)&g_MusicPlayer.decoder;
if (pDecoder == NULL) {
return;
}
if(frameCount<=0) return;
ma_uint64 framesRead;
ma_decoder_read_pcm_frames(pDecoder, pOutput, frameCount, &framesRead);
if(framesRead < frameCount) //This happens when the song ends.
g_MusicPlayer.songEnd();
(void)pInput;
}
//---------------------------------------------------------
// playing an audio file
void CMusic :: OpenFile ( const char *filename, int repeat )
{
audiofile_t *p = NULL;
p = new audiofile_t;
sprintf ( p->name, filename );
p->repeat = repeat;
p->next = m_pTrack;
m_pTrack = p;
}
//---------------------------------------------------------
// play a list of audio files
void CMusic :: OpenList ( const char *filename )
{
// open text file
FILE *myfile = fopen ( filename, "r" );
if ( myfile == NULL )
{
ALERT ( at_console, "MUSICPLAYER : impossible to load %s\n", filename );
return;
}
// saving songs to the list
int total = 0;
if ( fscanf ( myfile, "%i", &total ) != EOF )
{
for ( int i=0; i<total; i++ )
{
char ctitle [128];
int irepeat;
// reading the title
if ( fscanf ( myfile, "%s", ctitle ) != EOF )
{
if ( fscanf ( myfile, "%i", &irepeat ) != EOF )
OpenFile ( ctitle, irepeat );
else
break;
}
else
break;
}
}
// close text file
fclose ( myfile );
}
//---------------------------------------------------------
// end of the song
void CMusic :: songEnd ( )
{
// end of the song
g_MusicPlayer.Stop ();
// search for the first song in the list
audiofile_t *p = NULL;
p = g_MusicPlayer.m_pTrack;
while ( p != NULL )
{
if ( p->next == NULL )
break;
else
p = p->next;
}
if ( p == NULL )
{
ALERT ( at_console, "MUSICPLAYER : no song in the list\n" );
return;
}
// decrease repeat count
p->repeat --;
// removal of songs whose repeats ran off
if ( p->repeat < 1 )
{
if ( g_MusicPlayer.m_pTrack == p )
{
delete g_MusicPlayer.m_pTrack;
g_MusicPlayer.m_pTrack = NULL;
}
else
{
audiofile_t *q = NULL;
q = g_MusicPlayer.m_pTrack;
while ( q->next != p )
q = q->next;
delete q->next;
q->next = NULL;
}
}
// close player if list is empty
if ( g_MusicPlayer.m_pTrack == NULL )
{
g_MusicPlayer.Reset();
}
// next track start
else
{
g_MusicPlayer.Play();
}
return;
}
//---------------------------------------------------------
// initiate playback
void CMusic :: Play ( void )
{
if ( m_IsPlaying == TRUE )
return;
if ( m_bInit == FALSE )
{
Init ();
if ( m_bInit == FALSE )
{
ALERT ( at_console, "MUSICPLAYER : unable to initialize\n" );
return;
}
}
// search for the first song in the list
audiofile_t *p = NULL;
p = m_pTrack;
while ( p != NULL )
{
if ( p->next == NULL )
break;
else
p = p->next;
}
if ( p == NULL )
{
ALERT ( at_console, "MUSICPLAYER : no song in the list\n" );
return;
}
//Stop playback
m_IsPlaying = FALSE; //Pause playback.
ma_decoder_seek_to_pcm_frame(&decoder, 0); //Reset the file to start.
// loading file
char payload [512];
sprintf(payload, "%s", p->name);
ALERT ( at_console, "MUSICPLAYER : Opening file %s.\n", payload );
result = ma_decoder_init_file(payload, NULL, &decoder);
if (result != MA_SUCCESS) {
ALERT ( at_console, "MUSICPLAYER : %s : can not load file\n", p->name );
return;
}
//If the new track has different properties to the previous one.
if(
deviceConfig.playback.format != decoder.outputFormat ||
deviceConfig.playback.channels != decoder.outputChannels ||
deviceConfig.sampleRate != decoder.outputSampleRate
){
deviceConfig.playback.format = decoder.outputFormat; //Change device settings
deviceConfig.playback.channels = decoder.outputChannels;
deviceConfig.sampleRate = decoder.outputSampleRate;
ALERT ( at_console, "MUSICPLAYER : Changing format to %d, channels to %d and sample rate to %d.\n", deviceConfig.playback.format, deviceConfig.playback.channels, deviceConfig.sampleRate);
//Now we need to recreate the device to apply.
ma_device_uninit(&device); //This is crucial, failing to do this results in segFault.
if (ma_device_init(NULL, &deviceConfig, &device) != MA_SUCCESS) { //Apply new config.
ALERT ( at_console, "MUSICPLAYER : Failed to change playback device configuration.\n" );
g_MusicPlayer.m_bInit = FALSE; //We have been deinitialized. This is NOT ideal.
return;
}else
ALERT ( at_console, "MUSICPLAYER : New configuration applied successfully.\n");
}
// playback
if (ma_device_start(&device) != MA_SUCCESS) {
ALERT ( at_console, "MUSICPLAYER : Failed to start playback device.\n" );
m_IsPlaying = FALSE; //Pause playback.
ma_decoder_seek_to_pcm_frame(&decoder, 0); //Reset the file to start.
return;
}else{
m_IsPlaying = TRUE;
}
return;
}
void CMusic :: Stop ( void )
{
if ( m_IsPlaying == TRUE )
{
m_IsPlaying = FALSE; //Pause playback.
ma_decoder_seek_to_pcm_frame(&decoder, 0); //Reset the file to start.
}
}
void CMusic :: Reset ( void ) //Should instead be called "Next Track", but we keep Julien's naming.
{
//Reset the player.
if ( m_bInit == TRUE )
ALERT ( at_console, "MUSICPLAYER : Player reset.\n" );
Stop();
audiofile_t *p = NULL;
while ( m_pTrack != NULL )
{
p = m_pTrack;
m_pTrack = p->next;
delete p;
}
}
void CMusic :: Terminate ( void ) //Cleanup and dereference
{
ALERT ( at_console, "MUSICPLAYER : Terminating and unloading.\n" );
ma_device_uninit(&device);
ma_decoder_uninit(&decoder);
g_MusicPlayer.m_bInit = FALSE;
}
//---------------------------------------------------------
// entity class
class CTriggerMusic : public CPointEntity
{
public:
void Spawn ( void );
void KeyValue ( KeyValueData *pkvd );
void Use ( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value );
virtual int Save ( CSave &save );
virtual int Restore ( CRestore &restore );
static TYPEDESCRIPTION m_SaveData[];
string_t m_iFileName; // file path
int m_iFileType; // text file (list) or audio file
};
LINK_ENTITY_TO_CLASS( trigger_music, CTriggerMusic );
TYPEDESCRIPTION CTriggerMusic::m_SaveData[] =
{
DEFINE_FIELD( CTriggerMusic, m_iFileType, FIELD_INTEGER ),
DEFINE_FIELD( CTriggerMusic, m_iFileName, FIELD_STRING ),
};
IMPLEMENT_SAVERESTORE( CTriggerMusic, CPointEntity );
void CTriggerMusic :: Spawn( void )
{
pev->solid = SOLID_NOT;
pev->effects = EF_NODRAW;
}
void CTriggerMusic :: KeyValue( KeyValueData *pkvd )
{
if (FStrEq(pkvd->szKeyName, "filetype"))
{
m_iFileType = atoi(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else if (FStrEq(pkvd->szKeyName, "filename"))
{
m_iFileName = ALLOC_STRING(pkvd->szValue);
pkvd->fHandled = TRUE;
}
else
CPointEntity::KeyValue( pkvd );
}
void CTriggerMusic :: Use( CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useType, float value )
{
if ( g_MusicPlayer.m_IsPlaying == TRUE )
return;
if ( m_iFileType == MUSIC_AUDIO_FILE )
{
g_MusicPlayer.OpenFile ( STRING(m_iFileName), 1 );
}
else
{
g_MusicPlayer.OpenList ( STRING(m_iFileName) );
}
g_MusicPlayer.Play();
}
/*
code
@PointClass base( Targetname ) = trigger_music : "Trigger Music"
[
filetype(choices) : "File type" : 0 =
[
0: "File list (*.txt)"
1: "File wav mp2 mp3 ogg raw"
]
filename(string) : "Name (mod/folder/file.extension)"
]
*/
/*//---------------
Playlist contents
example: music01.txt file:
//
3
monmod/sound/mp3/music01_debut.mp3 1
monmod/sound/mp3/music01_boucle.mp3 3
monmod/sound/mp3/music01_fin.mp3 1
//
composition :
- total number of tracks
- path of the first music file
- times to repeat that file
- path of the second
- etc ...
*///---------------

83
dlls/musicminiaudio.h

@ -1,83 +0,0 @@ @@ -1,83 +0,0 @@
//-------------------------------------------------------------
//-------------------------------------------------------------
//-
//- musicminiaudio.h
//-
//-------------------------------------------------------------
//-------------------------------------------------------------
//- by Roy at suggestion by nekonomicon, based on code by JujU
//-------------------------------------------------------------
//- mp3 player code for HL mod
//-------------------------------------------------------------
//-
//- compatible with version 0.11.9 of Miniaudio
//- https://github.com/mackron/miniaudio
//-
//-------------------------------------------------------------
#ifndef MUSIC_H
#define MUSIC_H
#define MINIAUDIO_IMPLEMENTATION
#include "../miniaudio/miniaudio.h"
//---------------------------------------------------------
// defines
#define MUSIC_AUDIO_FILE 1
#define MUSIC_LIST_FILE 0
//---------------------------------------------------------
// audio file structure
struct audiofile_t
{
char name [128];
int repeat;
audiofile_t *next;
};
//---------------------------------------------------------
// reader class
class CMusic
{
public:
// reading functions
void OpenFile ( const char *filename, int repeat ); // open a single file
void OpenList ( const char *filename ); // opening a text file containing the files
void Init ( void ); // initialization
void Play ( void ); // playback
void Stop ( void ); // stop
void Reset ( void ); // pause and switch to next track
void Terminate ( void ); // clean-up during termination
// variables
BOOL m_IsPlaying; // monitors whether the music is played, used to pause the music
BOOL m_bInit; // checks if the player is initialized
audiofile_t *m_pTrack; // playlist items
// constructor / destructor
CMusic () { m_bInit = FALSE; m_IsPlaying = FALSE; m_pTrack = NULL; Reset(); };
~CMusic () { Terminate(); };
// object instances
ma_result result;
ma_decoder decoder;
ma_device_config deviceConfig;
ma_device device;
void songEnd();
};
extern CMusic g_MusicPlayer;
#endif // MUSIC_H
Loading…
Cancel
Save