508 lines
9.8 KiB
C
508 lines
9.8 KiB
C
/*
|
|
|
|
Copyright (C) 2004 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.
|
|
|
|
*/
|
|
|
|
/*
|
|
* wolf_aud.c: Decode Wolfenstein 3-D Adlib audio data.
|
|
*
|
|
* Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
|
|
* Date: 2004
|
|
*
|
|
* Acknowledgement:
|
|
* This code was derived from Wolfenstein 3-D, and was originally
|
|
* written by Id Software, Inc.
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "wolf_def.h"
|
|
|
|
#include "../string/com_string.h"
|
|
#include "../adlib/adlib.h"
|
|
#include "../adlib/fmopl.h"
|
|
#include "../loaders/wav.h"
|
|
#include "../filesys/file.h"
|
|
#include "../../../common/common_utils.h"
|
|
#include "../../../common/arch.h"
|
|
#include "../memory/memory.h"
|
|
|
|
#define AHEADFNAME "AUDIOHED"
|
|
#define AUDIOFNAME "AUDIOT"
|
|
|
|
|
|
#define MAX_CHUNK_SIZE 500
|
|
|
|
|
|
#define WL6_STARTMUSIC 262
|
|
#define SOD_STARTMUSIC 243
|
|
|
|
|
|
|
|
PRIVATE FILE *audiohandle;
|
|
|
|
PRIVATE W32 *audiostarts;
|
|
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function: CAL_SetupAudioFile() -Setup for decoding audio data.
|
|
|
|
Parameters: fextension -[in] Pointer to string with file extension.
|
|
|
|
Returns: Non-zero on success, otherwise zero.
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PRIVATE W8 CAL_SetupAudioFile( const char *fextension )
|
|
{
|
|
FILE *handle;
|
|
SW32 length;
|
|
W32 count;
|
|
char fname[ 13 ];
|
|
|
|
if( ! fextension || ! *fextension )
|
|
{
|
|
printf( "NULL extension passed into CAL_SetupAudioFile!\n" );
|
|
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// load audiohed.XXX (offsets and lengths for audio file)
|
|
//
|
|
cs_strlcpy( fname, AHEADFNAME, sizeof( fname ) );
|
|
cs_strlcat( fname, fextension, sizeof( fname ) );
|
|
|
|
handle = fopen( cs_strupr( fname ), "rb" );
|
|
if( handle == NULL )
|
|
{
|
|
handle = fopen( cs_strlwr( fname ), "rb" );
|
|
|
|
if( handle == NULL )
|
|
{
|
|
printf( "Can not open file (%s) for read!\n", fname );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
length = FS_FileLength( handle );
|
|
if( length < 4 )
|
|
{
|
|
fclose( handle );
|
|
printf( "Incorrect audio header size on file: %s\n", fname );
|
|
return 0;
|
|
}
|
|
|
|
audiostarts = (PW32) MM_MALLOC( length );
|
|
if( audiostarts == NULL )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
count = fread( audiostarts, sizeof( W32 ), length >> 2, handle );
|
|
if( count != (W32)(length >> 2) )
|
|
{
|
|
fclose( handle );
|
|
printf( "[Error]: Read error on file: (%s)", fname );
|
|
return 0;
|
|
}
|
|
|
|
|
|
fclose( handle );
|
|
|
|
//
|
|
// open the Audio data file
|
|
//
|
|
cs_strlcpy( fname, AUDIOFNAME, sizeof( fname ) );
|
|
cs_strlcat( fname, fextension, sizeof( fname ) );
|
|
|
|
audiohandle = fopen( cs_strupr( fname ), "rb" );
|
|
if( audiohandle == NULL )
|
|
{
|
|
audiohandle = fopen( cs_strlwr( fname ), "rb" );
|
|
if( audiohandle == NULL )
|
|
{
|
|
printf( "Could not open file (%s) for read!\n", fname );
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function: CA_CacheAudioChunk() -Cache audio data.
|
|
|
|
Parameters: chunk -[in] Chunk number to cache.
|
|
BuffChunk -[in] Allocated memory block to hold data.
|
|
|
|
Returns: Non-zero on success, otherwise zero.
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PRIVATE W8 CA_CacheAudioChunk( W32 chunk, W8 *BuffChunk )
|
|
{
|
|
W32 pos, length, count;
|
|
|
|
|
|
//
|
|
// load the chunk into a buffer
|
|
//
|
|
pos = audiostarts[ chunk ];
|
|
length = audiostarts[ chunk+1 ] - pos;
|
|
if( length < 1 || length > MAX_CHUNK_SIZE )
|
|
{
|
|
printf( "[CA_CacheAudioChunk]: Chunk length not valid\n" );
|
|
return 0;
|
|
}
|
|
|
|
|
|
if( fseek( audiohandle, pos, SEEK_SET ) != 0 )
|
|
{
|
|
printf( "[CA_CacheAudioChunk]: Could not seek!\n" );
|
|
return 0;
|
|
}
|
|
|
|
|
|
count = fread( BuffChunk, 1, length, audiohandle );
|
|
if( count != length )
|
|
{
|
|
printf( "[CA_CacheAudioChunk]: Read error!\n" );
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function: CA_SaveAudioChunk() -Decode and save audio data.
|
|
|
|
Parameters: chunk -[in] Chunk number to cache.
|
|
filename -[in] Save as filename.
|
|
BuffChunk -[in] Sound data to decode.
|
|
BuffWav -[in] Allocated memory block to hold decoded data.
|
|
|
|
Returns: Nothing.
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PRIVATE void CA_SaveAudioChunk( W32 chunk, const char *filename,
|
|
W8 *BuffChunk, W8 *BuffWav )
|
|
{
|
|
W32 length;
|
|
|
|
if( ! filename || ! *filename )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( ! CA_CacheAudioChunk( chunk, BuffChunk ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( ADLIB_DecodeSound( (AdLibSound *)BuffChunk, BuffWav, &length ) == 0 )
|
|
{
|
|
return;
|
|
}
|
|
|
|
write_wav( filename, BuffWav, length, 1, 22050, 2 );
|
|
}
|
|
|
|
|
|
extern W32 ADLIB_UpdateMusic( W32 size, void *buffer );
|
|
extern W32 ADLIB_getLength( void *musbuffer );
|
|
extern void ADLIB_LoadMusic( void *musbuffer );
|
|
|
|
extern int vorbis_encode( const char *filename, void *data, W32 size, W32 in_channels, W32 in_samplesize,
|
|
W32 rate, W32 quality, W32 max_bitrate, W32 min_bitrate );
|
|
|
|
|
|
#define NCH 1 // channels
|
|
#define BPS 16 // bit per second
|
|
|
|
PRIVATE void CA_SaveMusicChunk( W32 chunk, const char *filename )
|
|
{
|
|
W8 *data, *BuffWav;
|
|
W32 pos, length, uncompr_length;
|
|
W32 len;
|
|
|
|
|
|
pos = audiostarts[ chunk ];
|
|
length = audiostarts[ chunk+1 ] - pos;
|
|
|
|
data = MM_MALLOC( length );
|
|
if( data == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( fseek( audiohandle, pos, SEEK_SET ) != 0 )
|
|
{
|
|
printf( "[CA_SaveMusicChunk]: Could not seek!\n" );
|
|
|
|
MM_FREE( data );
|
|
|
|
return;
|
|
}
|
|
|
|
if( fread( data, 1, length, audiohandle ) != length )
|
|
{
|
|
printf( "[CA_SaveMusicChunk]: Read error!\n" );
|
|
|
|
MM_FREE( data );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
uncompr_length = ADLIB_getLength( data );
|
|
if( uncompr_length == 1 )
|
|
{
|
|
MM_FREE( data );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
ADLIB_LoadMusic( data );
|
|
|
|
BuffWav = MM_MALLOC( uncompr_length * 64 * 2 );
|
|
if( BuffWav == NULL )
|
|
{
|
|
MM_FREE( data );
|
|
|
|
return;
|
|
}
|
|
|
|
len = ADLIB_UpdateMusic( uncompr_length, BuffWav );
|
|
|
|
|
|
#if 1
|
|
|
|
vorbis_encode( filename, BuffWav, len, 1, 16, 44100, 0, 0, 0 );
|
|
|
|
#else
|
|
|
|
write_wav( filename, BuffWav, len, 1, 44100, 2 );
|
|
|
|
#endif
|
|
|
|
MM_FREE( BuffWav );
|
|
MM_FREE( data );
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function: CAL_ShutdownAudioFile() -Decode and save audio data.
|
|
|
|
Parameters: Nothing.
|
|
|
|
Returns: Nothing.
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PRIVATE void CAL_ShutdownAudioFile()
|
|
{
|
|
if( audiohandle )
|
|
{
|
|
fclose( audiohandle );
|
|
audiohandle = NULL;
|
|
}
|
|
|
|
if( audiostarts )
|
|
{
|
|
MM_FREE( audiostarts );
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function: AudioRipper() -Interface to audio decoder.
|
|
|
|
Parameters: fextension -[in] file extension string.
|
|
start -[in] Chunk number for start of audio data.
|
|
end -[in] Chunk number for end of audio data.
|
|
|
|
Returns: Nothing.
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC _boolean AudioRipper( const char *fextension,
|
|
W32 start, W32 end, W16 version )
|
|
{
|
|
W32 i, j;
|
|
char filename[ 64 ];
|
|
W8 *buffChunk;
|
|
W8 *buffWav;
|
|
W32 startofmusic = WL6_STARTMUSIC - 1;
|
|
W32 endofmusic = LASTMUSIC;
|
|
|
|
//
|
|
// Setup
|
|
//
|
|
|
|
if( version == SOD_PAK || version == SDM_PAK )
|
|
{
|
|
if( 0 == FS_Mkdir( SODLSFXDIR ) )
|
|
{
|
|
printf( "[%s] Could not create directory (%s)!\n", "wolf_aud.c", SODLSFXDIR );
|
|
|
|
return false;
|
|
}
|
|
|
|
startofmusic = SOD_STARTMUSIC;
|
|
endofmusic = SOD_LASTMUSIC;
|
|
}
|
|
else
|
|
{
|
|
if( 0 == FS_Mkdir( LSFXDIR ) )
|
|
{
|
|
printf( "[%s] Could not create directory (%s)!\n", "wolf_aud.c", LSFXDIR );
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
if( 0 == FS_Mkdir( MUSICDIR ) )
|
|
{
|
|
printf( "[%s] Could not create directory (%s)!\n", "wolf_aud.c", LSFXDIR );
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if( ! CAL_SetupAudioFile( fextension ) )
|
|
{
|
|
CAL_ShutdownAudioFile();
|
|
|
|
return false;
|
|
}
|
|
|
|
if( ! ADLIB_Init( 22050 ) )
|
|
{
|
|
CAL_ShutdownAudioFile();
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Allocate buffers
|
|
//
|
|
|
|
buffChunk = MM_MALLOC( MAX_CHUNK_SIZE );
|
|
if( buffChunk == NULL )
|
|
{
|
|
ADLIB_Shutdown();
|
|
CAL_ShutdownAudioFile();
|
|
|
|
return false;
|
|
}
|
|
|
|
buffWav = MM_MALLOC( MAX_WAV_SIZE );
|
|
if( buffWav == NULL )
|
|
{
|
|
ADLIB_Shutdown();
|
|
CAL_ShutdownAudioFile();
|
|
MM_FREE( buffChunk );
|
|
|
|
return false;
|
|
}
|
|
|
|
//
|
|
// Decode Audio data
|
|
//
|
|
|
|
printf( "Decoding Audio Data...\n" );
|
|
|
|
for( i = start, j = 0; i < end; ++i, ++j )
|
|
{
|
|
if( version == SOD_PAK || version == SDM_PAK )
|
|
{
|
|
cs_snprintf( filename, sizeof( filename ), "%s/%.3d.wav", SODLSFXDIR, j );
|
|
}
|
|
else
|
|
{
|
|
cs_snprintf( filename, sizeof( filename ), "%s/%.3d.wav", LSFXDIR, j );
|
|
}
|
|
|
|
CA_SaveAudioChunk( i, filename, buffChunk, buffWav );
|
|
}
|
|
|
|
ADLIB_Shutdown();
|
|
|
|
MM_FREE( buffWav );
|
|
MM_FREE( buffChunk );
|
|
|
|
|
|
//
|
|
// Decode Music data
|
|
//
|
|
|
|
if( ! ADLIB_Init( 44100 ) )
|
|
{
|
|
CAL_ShutdownAudioFile();
|
|
|
|
return false;
|
|
}
|
|
|
|
printf( "Decoding Music Data...\n" );
|
|
|
|
for( i = 0 ; i < endofmusic ; ++i )
|
|
{
|
|
if( version == SOD_PAK || version == SDM_PAK )
|
|
{
|
|
cs_snprintf( filename, sizeof( filename ), "%s/%s.ogg", MUSICDIR, GetMusicFileName_SOD( i ) );
|
|
}
|
|
else
|
|
{
|
|
cs_snprintf( filename, sizeof( filename ), "%s/%s.ogg", MUSICDIR, GetMusicFileName_WL6( i ) );
|
|
}
|
|
|
|
CA_SaveMusicChunk( startofmusic + i, filename );
|
|
}
|
|
|
|
ADLIB_Shutdown();
|
|
|
|
//
|
|
// Shutdown
|
|
//
|
|
|
|
|
|
CAL_ShutdownAudioFile();
|
|
|
|
|
|
|
|
return true;
|
|
}
|