mirror of
https://github.com/YGGverse/hlsdk-portable.git
synced 2025-03-13 05:51:19 +00:00
HL:Invasion Update Miniaudio implementation and remove GStreamer / FMod
This commit is contained in:
parent
f080ec41b1
commit
418ae2d41d
@ -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
27
README.md
@ -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:
|
||||
|
||||
|
@ -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
|
||||
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()
|
||||
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
1091
dlls/fmod.h
File diff suppressed because it is too large
Load Diff
@ -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
|
464
dlls/music.cpp
464
dlls/music.cpp
@ -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.
|
||||
#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);
|
||||
|
||||
|
||||
//Fake functions to have something to work with on Linux
|
||||
//---------------------------------------------------------
|
||||
// initialisation
|
||||
|
||||
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 )
|
||||
void CMusic :: Init ( void )
|
||||
{
|
||||
return TRUE;
|
||||
|
||||
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;
|
||||
}
|
||||
void CMusic :: Play ( void ){}
|
||||
void CMusic :: Stop ( void ){}
|
||||
void CMusic :: Reset ( void ){}
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// The actual game entity
|
||||
// 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;
|
||||
}
|
||||
#endif //End if #ifndef DISABLE_MINIAUDIO
|
||||
|
||||
//---------------------------------------------------------
|
||||
// entity class
|
||||
|
||||
|
||||
|
||||
@ -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 );
|
||||
|
||||
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 )
|
||||
|
||||
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
74
dlls/music.h
@ -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 @@
|
||||
#define MUSIC_LIST_FILE 0
|
||||
|
||||
//---------------------------------------------------------
|
||||
// structure of the audio file entity
|
||||
// audio file structure
|
||||
|
||||
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; // monitors whether the music is played, used to pause the music
|
||||
BOOL m_bInit; // checks if the player is initialized
|
||||
|
||||
BOOL m_IsPlaying; // t
|
||||
BOOL m_bInit; // t
|
||||
audiofile_t *m_pTrack; // playlist items
|
||||
|
||||
audiofile_t *m_pTrack; //current track
|
||||
|
||||
// constructor & destructor
|
||||
// constructor / destructor
|
||||
|
||||
CMusic () { m_bInit = FALSE; m_IsPlaying = FALSE; m_pTrack = NULL; Reset(); };
|
||||
~CMusic () {};
|
||||
~CMusic () { Terminate(); };
|
||||
|
||||
// functions import
|
||||
// none, see window / Julien's code.
|
||||
// object instances
|
||||
|
||||
ma_result result;
|
||||
ma_decoder decoder;
|
||||
ma_device_config deviceConfig;
|
||||
ma_device device;
|
||||
|
||||
void songEnd();
|
||||
};
|
||||
|
||||
extern CMusic g_MusicPlayer;
|
||||
|
@ -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 ...
|
||||
|
||||
*///---------------
|
@ -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
|
@ -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 ...
|
||||
|
||||
*///---------------
|
@ -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
|
@ -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 ...
|
||||
|
||||
*///---------------
|
@ -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…
x
Reference in New Issue
Block a user