mirror of
https://github.com/id-Software/Wolf3D-iOS.git
synced 2026-03-20 00:49:35 +01:00
Source release of Wolfenstein 3D Classic Platinum for iOS, 1.1
This commit is contained in:
516
wolf3d/code/env/sound_stream.c
vendored
Normal file
516
wolf3d/code/env/sound_stream.c
vendored
Normal file
@@ -0,0 +1,516 @@
|
||||
/*
|
||||
|
||||
Copyright (C) 2005 Michael Liebscher
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
* sound_stream.c: Sound Stream manager.
|
||||
*
|
||||
* Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
|
||||
* Date: 2004
|
||||
*
|
||||
* Acknowledgement:
|
||||
* Portion of this code was derived from Quake II Evolved.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../wolfiphone.h"
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char introName[ MAX_GAMEPATH ];
|
||||
char loopName[ MAX_GAMEPATH ];
|
||||
_boolean looping;
|
||||
|
||||
filehandle_t *hFile;
|
||||
|
||||
|
||||
int start;
|
||||
int rate;
|
||||
unsigned format;
|
||||
void *vorbisFile;
|
||||
|
||||
} musicTrack_t;
|
||||
|
||||
|
||||
// anything greater than 1<<13 caused crashes on iphone OS 2.1 (on a 3G iphone)
|
||||
#define BUFFER_SIZE (1<<11)
|
||||
|
||||
PRIVATE musicTrack_t bgTrack;
|
||||
|
||||
PRIVATE channel_t *s_streamingChannel;
|
||||
|
||||
|
||||
extern void Sound_StopBGTrack( void );
|
||||
|
||||
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: ovc_read -OGG read Callback. Reads data from a stream.
|
||||
|
||||
Parameters:
|
||||
ptr -[in] Storage location for data.
|
||||
size -[in] Item size in bytes.
|
||||
nmemb -[in] Maximum number of items to be read.
|
||||
datasource -[in] music track data structure.
|
||||
|
||||
Returns: Nothing
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PRIVATE size_t ovc_read( void *ptr, size_t size, size_t nmemb, void *datasource )
|
||||
{
|
||||
musicTrack_t *track = (musicTrack_t *)datasource;
|
||||
|
||||
|
||||
if( ! size || ! nmemb )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
return FS_ReadFile( ptr, size, nmemb, track->hFile );
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: ovc_read -OGG seek Callback. Moves the file pointer to a specified
|
||||
location.
|
||||
|
||||
Parameters:
|
||||
datasource -[in] music track data structure.
|
||||
offset -[in] Number of bytes from whence.
|
||||
whence -[in] Initial position.
|
||||
|
||||
|
||||
Returns:
|
||||
If successful, fseek returns 0. Otherwise, it returns a nonzero
|
||||
value.
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PRIVATE int ovc_seek( void *datasource, ogg_int64_t offset, int whence )
|
||||
{
|
||||
musicTrack_t *track = (musicTrack_t *)datasource;
|
||||
|
||||
return FS_FileSeek( track->hFile, offset, whence );
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: ovc_close -OGG close Callback. Closes a stream.
|
||||
|
||||
Parameters: datasource -[in] music track data structure.
|
||||
|
||||
Returns: 0 if the stream is successfully closed, otherwise nonzero.
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PRIVATE int ovc_close( void *datasource )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: ovc_tell -OGG tell Callback. Gets the current position of a file
|
||||
pointer.
|
||||
|
||||
Parameters: datasource -[in] music track data structure.
|
||||
|
||||
Returns: The current file position.
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PRIVATE long ovc_tell( void *datasource )
|
||||
{
|
||||
musicTrack_t *track = (musicTrack_t *)datasource;
|
||||
|
||||
return FS_FileTell( track->hFile );
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: Sound_OpenBGTrack -OGG read Callback.
|
||||
|
||||
Parameters:
|
||||
name -[in] File name to open.
|
||||
track -[in/out] Music track data structure.
|
||||
|
||||
Returns: False on error, otherwise true.
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PRIVATE _boolean Sound_OpenBGTrack( const char *name, musicTrack_t *track )
|
||||
{
|
||||
OggVorbis_File *vorbisFile;
|
||||
vorbis_info *vorbisInfo;
|
||||
ov_callbacks vorbisCallbacks = {ovc_read, ovc_seek, ovc_close, ovc_tell};
|
||||
int ret;
|
||||
extern cvar_t *music;
|
||||
|
||||
if ( music->value == 0 || SysIPhoneOtherAudioIsPlaying() ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
track->hFile = FS_OpenFile( name, 0 );
|
||||
if( ! track->hFile )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
track->vorbisFile = vorbisFile = Z_Malloc( sizeof( OggVorbis_File ) );
|
||||
|
||||
if( (ret = ov_open_callbacks( track, vorbisFile, NULL, 0, vorbisCallbacks )) < 0 )
|
||||
{
|
||||
switch( ret )
|
||||
{
|
||||
case OV_EREAD:
|
||||
Com_DPrintf( "A read from media returned an error.(%s)\n", name );
|
||||
break;
|
||||
case OV_ENOTVORBIS:
|
||||
Com_DPrintf( "Bitstream is not Vorbis data.(%s)\n", name );
|
||||
break;
|
||||
case OV_EVERSION:
|
||||
Com_DPrintf( "Vorbis version mismatch.(%s)\n", name );
|
||||
break;
|
||||
case OV_EBADHEADER:
|
||||
Com_DPrintf( "Invalid Vorbis bitstream header.(%s)\n", name );
|
||||
break;
|
||||
case OV_EFAULT:
|
||||
Com_DPrintf( "Internal logic fault; indicates a bug or heap/stack corruption.(%s)\n", name );
|
||||
break;
|
||||
|
||||
}
|
||||
Com_DPrintf( "Could not open OGG stream (%s)\n", name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
vorbisInfo = ov_info( vorbisFile, -1 );
|
||||
if( vorbisInfo->channels != 1 && vorbisInfo->channels != 2 )
|
||||
{
|
||||
Com_DPrintf( "Only mono and stereo OGG files supported (%s)\n", name );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
track->start = ov_raw_tell( vorbisFile );
|
||||
track->rate = vorbisInfo->rate;
|
||||
track->format = (vorbisInfo->channels == 2) ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: Sound_CloseBGTrack -Close out background music track.
|
||||
|
||||
Parameters: track -[in] Music track to close.
|
||||
|
||||
Returns: Nothing
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PRIVATE void Sound_CloseBGTrack( musicTrack_t *track )
|
||||
{
|
||||
if( track->vorbisFile )
|
||||
{
|
||||
ov_clear( track->vorbisFile );
|
||||
|
||||
Z_Free( track->vorbisFile );
|
||||
track->vorbisFile = NULL;
|
||||
}
|
||||
|
||||
if( track->hFile )
|
||||
{
|
||||
FS_CloseFile( track->hFile );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: Sound_StreamBGTrack -Called each frame to update streaming music
|
||||
track.
|
||||
|
||||
Parameters: Nothing
|
||||
|
||||
Returns: Nothing
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PUBLIC void Sound_StreamBGTrack( void )
|
||||
{
|
||||
|
||||
W8 data[BUFFER_SIZE];
|
||||
int processed, queued, state;
|
||||
int size, read, dummy;
|
||||
unsigned buffer;
|
||||
|
||||
if( ! s_musicVolume->value )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( ! s_streamingChannel )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Unqueue and delete any processed buffers
|
||||
pfalGetSourcei( s_streamingChannel->sourceName, AL_BUFFERS_PROCESSED, &processed );
|
||||
if( processed > 0 )
|
||||
{
|
||||
while (processed--)
|
||||
{
|
||||
pfalSourceUnqueueBuffers( s_streamingChannel->sourceName, 1, &buffer );
|
||||
pfalDeleteBuffers( 1, &buffer );
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we always have at least 4 buffers in the queue
|
||||
pfalGetSourcei( s_streamingChannel->sourceName, AL_BUFFERS_QUEUED, &queued );
|
||||
while( queued < 4 )
|
||||
{
|
||||
size = 0;
|
||||
|
||||
// Stream from disk
|
||||
while( size < BUFFER_SIZE )
|
||||
{
|
||||
read = ov_read( bgTrack.vorbisFile, (char *)data + size, BUFFER_SIZE - size, &dummy );
|
||||
if( read == 0 )
|
||||
{
|
||||
// End of file
|
||||
if( ! bgTrack.looping)
|
||||
{
|
||||
// Close the intro track
|
||||
Sound_CloseBGTrack( &bgTrack );
|
||||
|
||||
// Open the loop track
|
||||
if( ! Sound_OpenBGTrack( bgTrack.loopName, &bgTrack ) )
|
||||
{
|
||||
Sound_StopBGTrack();
|
||||
return;
|
||||
}
|
||||
|
||||
bgTrack.looping = true;
|
||||
}
|
||||
|
||||
// Restart the track, skipping over the header
|
||||
ov_raw_seek( bgTrack.vorbisFile, (ogg_int64_t)bgTrack.start );
|
||||
|
||||
// Try streaming again
|
||||
read = ov_read( bgTrack.vorbisFile, (char *)data + size, BUFFER_SIZE - size, &dummy );
|
||||
}
|
||||
|
||||
if( read <= 0 )
|
||||
{
|
||||
// An error occurred
|
||||
Sound_StopBGTrack();
|
||||
return;
|
||||
}
|
||||
|
||||
size += read;
|
||||
}
|
||||
|
||||
// Upload and queue the new buffer
|
||||
pfalGenBuffers( 1, &buffer );
|
||||
pfalBufferData( buffer, bgTrack.format, data, size, bgTrack.rate );
|
||||
pfalSourceQueueBuffers( s_streamingChannel->sourceName, 1, &buffer );
|
||||
|
||||
queued++;
|
||||
}
|
||||
|
||||
// Update volume
|
||||
pfalSourcef( s_streamingChannel->sourceName, AL_GAIN, s_musicVolume->value );
|
||||
|
||||
// If not playing, then do so
|
||||
pfalGetSourcei( s_streamingChannel->sourceName, AL_SOURCE_STATE, &state );
|
||||
if( state != AL_PLAYING )
|
||||
{
|
||||
pfalSourcePlay(s_streamingChannel->sourceName);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: Sound_StartStreaming -Start streaming background music track.
|
||||
|
||||
Parameters: Nothing
|
||||
|
||||
Returns: Nothing
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PUBLIC void Sound_StartStreaming( void )
|
||||
{
|
||||
if( ! sound_initialized )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( s_streamingChannel )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s_streamingChannel = Sound_PickChannel( 0, 0 );
|
||||
if( ! s_streamingChannel )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s_streamingChannel->streaming = true;
|
||||
|
||||
// hmmm...
|
||||
pfalDeleteSources( 1, &s_streamingChannel->sourceName );
|
||||
pfalGenSources( 1, &s_streamingChannel->sourceName );
|
||||
|
||||
// Set up the source
|
||||
pfalSourcei( s_streamingChannel->sourceName, AL_BUFFER, 0 );
|
||||
pfalSourcei( s_streamingChannel->sourceName, AL_LOOPING, AL_FALSE );
|
||||
pfalSourcei( s_streamingChannel->sourceName, AL_SOURCE_RELATIVE, AL_TRUE );
|
||||
pfalSourcefv( s_streamingChannel->sourceName, AL_POSITION, vec3_origin );
|
||||
pfalSourcefv( s_streamingChannel->sourceName, AL_VELOCITY, vec3_origin );
|
||||
pfalSourcef( s_streamingChannel->sourceName, AL_REFERENCE_DISTANCE, 1.0 );
|
||||
pfalSourcef( s_streamingChannel->sourceName, AL_MAX_DISTANCE, 1.0 );
|
||||
pfalSourcef( s_streamingChannel->sourceName, AL_ROLLOFF_FACTOR, 0.0 );
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: Sound_StopStreaming -Stop playing streaming music track.
|
||||
|
||||
Parameters: Nothing
|
||||
|
||||
Returns: Nothing
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PUBLIC void Sound_StopStreaming( void )
|
||||
{
|
||||
int processed;
|
||||
unsigned buffer;
|
||||
|
||||
if( ! sound_initialized )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( ! s_streamingChannel )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
s_streamingChannel->streaming = false;
|
||||
|
||||
|
||||
pfalSourceStop( s_streamingChannel->sourceName );
|
||||
|
||||
pfalGetSourcei( s_streamingChannel->sourceName, AL_BUFFERS_PROCESSED, &processed );
|
||||
if( processed > 0 )
|
||||
{
|
||||
while( processed-- )
|
||||
{
|
||||
pfalSourceUnqueueBuffers( s_streamingChannel->sourceName, 1, &buffer );
|
||||
pfalDeleteBuffers( 1, &buffer );
|
||||
}
|
||||
}
|
||||
|
||||
pfalSourcei( s_streamingChannel->sourceName, AL_BUFFER, 0 );
|
||||
|
||||
// hmmm...
|
||||
pfalDeleteSources( 1, &s_streamingChannel->sourceName );
|
||||
pfalGenSources( 1, &s_streamingChannel->sourceName );
|
||||
|
||||
s_streamingChannel = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: Sound_StartBGTrack -Play background music track.
|
||||
|
||||
Parameters:
|
||||
introTrack -[in] File name of intro track.
|
||||
loopTrack -[in] File name of loop track.
|
||||
|
||||
Returns: Nothing
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PUBLIC void Sound_StartBGTrack( const char *introTrack, const char *loopTrack )
|
||||
{
|
||||
if( ! sound_initialized )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Sound_StopBGTrack();
|
||||
|
||||
|
||||
my_strlcpy( bgTrack.introName, introTrack, sizeof( bgTrack.introName ) );
|
||||
my_strlcpy( bgTrack.loopName, loopTrack, sizeof( bgTrack.loopName) );
|
||||
|
||||
Sound_StartStreaming();
|
||||
|
||||
if( ! Sound_OpenBGTrack( bgTrack.introName, &bgTrack ) )
|
||||
{
|
||||
Sound_StopBGTrack();
|
||||
return;
|
||||
}
|
||||
|
||||
Sound_StreamBGTrack();
|
||||
}
|
||||
|
||||
/*
|
||||
-----------------------------------------------------------------------------
|
||||
Function: Sound_StopBGTrack -Stop playing background track.
|
||||
|
||||
Parameters: Nothing
|
||||
|
||||
Returns: Nothing
|
||||
|
||||
Notes:
|
||||
-----------------------------------------------------------------------------
|
||||
*/
|
||||
PUBLIC void Sound_StopBGTrack( void )
|
||||
{
|
||||
if( ! sound_initialized )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Sound_StopStreaming();
|
||||
|
||||
Sound_CloseBGTrack( &bgTrack );
|
||||
|
||||
memset( &bgTrack, 0, sizeof( musicTrack_t ) );
|
||||
}
|
||||
Reference in New Issue
Block a user