Portable Half-Life SDK. GoldSource and Xash3D. Crossplatform.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

511 lines
9.1 KiB

//---------------------------------------------------------
//---------------------------------------------------------
//- ---
//- 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 ...
*///---------------