/* * S_StartBackgroundTrack */ void S_StartBackgroundTrack( const char *intro, const char *loop, int mode ) { const char *ext; bgTrack_t *introTrack, *loopTrack; bgTrack_t *firstTrack = NULL; S_StopBackgroundTrack(); if( !intro || !intro[0] ) { return; } s_bgTrackMuted = false; s_bgTrackPaused = false; ext = COM_FileExtension( intro ); if( ext && !Q_stricmp( ext, ".m3u" ) ) { // mode bits: // 1 - shuffle // 2 - loop the selected track // 4 - stream (even if muted) firstTrack = S_ReadPlaylistFile( intro, mode & 1 ? true : false, mode & 2 ? true : false ); if( firstTrack ) { goto start_playback; } } // the intro track loops unless another loop track has been specified introTrack = S_AllocTrack( intro ); introTrack->loop = true; introTrack->next = introTrack->prev = introTrack; introTrack->muteOnPause = introTrack->isUrl || mode & 4 ? true : false; if( loop && loop[0] && Q_stricmp( intro, loop ) ) { loopTrack = S_AllocTrack( loop ); if( S_OpenMusicTrack( loopTrack, NULL ) ) { S_CloseMusicTrack( loopTrack ); introTrack->next = introTrack->prev = loopTrack; introTrack->loop = false; loopTrack->loop = true; loopTrack->muteOnPause = loopTrack->isUrl || mode & 4 ? true : false; loopTrack->next = loopTrack->prev = loopTrack; } } firstTrack = introTrack; start_playback: if( !firstTrack || firstTrack->ignore ) { S_StopBackgroundTrack(); return; } S_OpenBackgroundTrackTask( firstTrack ); }
/* * S_ReadPlaylistFile */ static bgTrack_t *S_ReadPlaylistFile( const char *filename, bool shuffle, bool loop ) { int filenum, length; char *tmpname = 0; size_t tmpname_size = 0; char *data, *line, *entry; playlistItem_t items[MAX_PLAYLIST_ITEMS]; int i, numItems = 0; length = trap_FS_FOpenFile( filename, &filenum, FS_READ ); if( length < 0 ) return NULL; // load the playlist into memory data = S_Malloc( length + 1 ); trap_FS_Read( data, length, filenum ); trap_FS_FCloseFile( filenum ); srand( time( NULL ) ); while( *data ) { size_t s; entry = data; // read the whole line for( line = data; *line != '\0' && *line != '\n'; line++ ); // continue reading from the next character, if possible data = (*line == '\0' ? line : line + 1); *line = '\0'; // trim whitespaces, tabs, etc entry = Q_trim( entry ); // special M3U entry or comment if( !*entry || *entry == '#' ) continue; if( trap_FS_IsUrl( entry ) ) { items[numItems].track = S_AllocTrack( entry ); } else { // append the entry name to playlist path s = strlen( filename ) + 1 + strlen( entry ) + 1; if( s > tmpname_size ) { if( tmpname ) S_Free( tmpname ); tmpname_size = s; tmpname = S_Malloc( tmpname_size ); } Q_strncpyz( tmpname, filename, tmpname_size ); COM_StripFilename( tmpname ); Q_strncatz( tmpname, "/", tmpname_size ); Q_strncatz( tmpname, entry, tmpname_size ); COM_SanitizeFilePath( tmpname ); items[numItems].track = S_AllocTrack( tmpname ); } if( ++numItems == MAX_PLAYLIST_ITEMS ) break; } if( tmpname ) { S_Free( tmpname ); tmpname = NULL; } if( !numItems ) return NULL; // set the playing order for( i = 0; i < numItems; i++ ) items[i].order = (shuffle ? (rand() % numItems) : i); // sort the playlist R_SortPlaylistItems( numItems, items ); // link the playlist for( i = 1; i < numItems; i++ ) { items[i-1].track->next = items[i].track; items[i].track->prev = items[i-1].track; items[i].track->loop = loop; } items[numItems-1].track->next = items[0].track; items[0].track->prev = items[numItems-1].track; items[0].track->loop = loop; return items[0].track; }
void S_StartBackgroundTrack( const char *intro, const char *loop ) { int count; const char *ext; bgTrack_t *t, f; bgTrack_t *introTrack, *loopTrack; ALenum error; int mode = 0; // Stop any existing music that might be playing S_StopBackgroundTrack(); if( !intro || !intro[0] ) return; s_bgTrackPaused = qfalse; ext = COM_FileExtension( intro ); if( ext && !Q_stricmp( ext, ".m3u" ) ) { // mode bits: // 1 - shuffle // 2 - loop the selected track if( loop && loop[0] ) mode = atoi( loop ); if( S_ReadPlaylistFile( intro, mode & 1 ? qtrue : qfalse ) ) goto start_playback; } // the intro track loops unless another loop track has been specified introTrack = S_AllocTrack( intro ); introTrack->next = introTrack->prev = introTrack; if( loop && loop[0] && Q_stricmp( intro, loop ) ) { loopTrack = S_AllocTrack( loop ); if( S_OpenMusicTrack( loopTrack ) ) { S_CloseMusicTrack( loopTrack ); loopTrack->next = introTrack->next = introTrack->prev = loopTrack; loopTrack->prev = introTrack; } } s_bgTrack = introTrack; start_playback: // this effectively precaches the first 15 scheduled tracks in the playlist for( count = 0, t = s_bgTrack; count < 15 && t && t != s_bgTrack; count++ ) { if( !t->isUrl ) { S_OpenMusicTrack( t ); if( t->next == t || t->next == s_bgTrack ) break; // break on an endless loop or full cycle if( !t->ignore && ( mode & 2 ) ) { // no point in precaching the whole playlist when we're only going // to loop one single track break; } } t = t->next; } // start playback with the first valid track if( count > 1 ) { memset( &f, 0, sizeof( f ) ); f.next = s_bgTrack; s_bgTrack = S_NextMusicTrack( &f ); } else { S_OpenMusicTrack( s_bgTrack ); } if( !s_bgTrack || s_bgTrack->ignore ) { S_StopBackgroundTrack(); return; } if( mode & 2 ) { // loop the same track over and over s_bgTrack->next = s_bgTrack->prev = s_bgTrack; } music_source_get(); if( !src ) { Com_Printf( "Error couldn't get source for music\n" ); S_StopBackgroundTrack(); return; } alloced_buffers = qfalse; queued_buffers = qfalse; qalGenBuffers( MUSIC_BUFFERS, buffers ); if( ( error = qalGetError() ) != AL_NO_ERROR ) { Com_Printf( "Error couldn't generate music buffers (%s)\n", S_ErrorMessage( error ) ); S_StopBackgroundTrack(); return; } alloced_buffers = qtrue; }