Added flac support. Split sound_server.c into smaller files. Fixed hang of linux version, if dsp is in use.

This commit is contained in:
johns 2002-03-26 01:01:04 +00:00
parent 6de4d81eb0
commit 48ebd8fbba
9 changed files with 948 additions and 386 deletions

View file

@ -747,6 +747,10 @@
<LI>Fixed bug: Add to selections with shift and rectangle didn't work.
<LI>Fixed bug: Units have wrong colors, if level is loaded with GUI.
<LI>Fixed many doxygen warnings.
<LI>Flac audio format added.
<LI>Linux sound driver now didn't block if dsp in use. Blocks if command
line option -w is used.
<LI>Split sound_server.c into wav.c, oss_audio.c and sdl_audio.c.
<LI>+++
</UL>
</UL>

View file

@ -34,16 +34,21 @@
-- Includes
----------------------------------------------------------------------------*/
#ifdef USE_THREAD
#if defined(USE_THREAD) && !defined(USE_SDLA)
#include <pthread.h>
#include <semaphore.h>
extern sem_t SoundThreadChannelSemaphore;
#endif
#include "sound_id.h"
/*----------------------------------------------------------------------------
-- Definitons
----------------------------------------------------------------------------*/
/**
** Maximal volume value
*/
#define MaxVolume 255
/**
@ -54,12 +59,12 @@ typedef struct _sample_ {
unsigned char SampleSize; /// sample size in bits
unsigned int Frequency; /// frequency in hz
unsigned int Length; /// sample length
char Data[0]; /// sample bytes
char Data[1]; /// sample bytes
} Sample;
/**
** Sound double group: a sound that groups two sounds, used to implement
** the annoyed/selected sound system of WC
** Sound double group: a sound that groups two sounds, used to implement
** the annoyed/selected sound system of WC
*/
typedef struct _two_groups_ {
struct _sound_ *First; /// first group: selected sound
@ -84,17 +89,21 @@ typedef struct _two_groups_ {
** the maximum range value
*/
#define MAX_SOUND_RANGE 254
/**
** Sound definition.
*/
typedef struct _sound_ {
unsigned char Range; /// Range is a multiplier for DistanceSilent
/// 255 means infinite range
unsigned Number ; /// 0 means 1, 1 means two groups and > 1 is a number
/**
** Range is a multiplier for ::DistanceSilent.
** 255 means infinite range of the sound.
*/
unsigned char Range; /// Range is a multiplier for DistanceSilent
unsigned char Number; /// single, group, or table of sounds.
union {
Sample* OneSound; /// if it's only a simple sound
Sample** OneGroup; /// when it's a simple group
TwoGroups* TwoGroups; /// when it's a double group
Sample* OneSound; /// if it's only a simple sound
Sample** OneGroup; /// when it's a simple group
TwoGroups* TwoGroups; /// when it's a double group
} Sound;
} Sound;
@ -107,7 +116,7 @@ typedef Sound* ServerSoundId;
** Origin of a sound
*/
typedef struct _origin_ {
const void* Base; /// pointer on a Unit
const void* Base; /// pointer on a Unit
unsigned Id; /// unique identifier (if the pointer has been shared)
} Origin;
@ -184,14 +193,16 @@ extern int NumCDTracks;
----------------------------------------------------------------------------*/
/// Register a sound (can be a simple sound or a group)
extern SoundId RegisterSound(char* file[],unsigned char number);
extern SoundId RegisterSound(char* file[],unsigned number);
/** Ask the sound server to put together to sounds to form a special sound.
@param first first part of the group
@param second second part of the group
@return the special sound unique identifier
*/
extern SoundId RegisterTwoGroups(SoundId first,SoundId second);
/**
** Ask the sound server to put together two sounds to form a special sound.
** @param first first part of the group
** @param second second part of the group
** @return the special sound unique identifier
** @brief Create a special sound group with two sounds
*/
extern SoundId RegisterTwoGroups(const SoundId first,const SoundId second);
/** Ask the sound server to change the range of a sound.
@param sound the id of the sound to modify.
@ -199,13 +210,14 @@ extern SoundId RegisterTwoGroups(SoundId first,SoundId second);
*/
extern void SetSoundRange(SoundId sound,unsigned char range);
/** Initialize the sound card.
*/
/// Initialize the sound card.
extern int InitSound(void);
/// Initialize the oss compatible sound card.
extern int InitOssSound(const char* dev,int freq,int size,int wait);
/// Initialize the sound card with SDL support.
extern int InitSdlSound(const char* dev,int freq,int size,int wait);
/** Initialize the sound server.
*/
/// Initialize the sound server.
extern int InitSoundServer(void);
/** Ask the sound layer to write the content of its buffer to the sound
@ -230,7 +242,9 @@ extern void QuitSound(void);
#define QuitSound() /// Dummy macro for without sound
#endif // { WITH_SOUND
#endif // } WITH_SOUND
extern int WaitForSoundDevice; /// Block until sound device available
/// Check the cdrom status
extern void CDRomCheck(void);

View file

@ -34,7 +34,7 @@ MODULE = sound
HDRS = libcda.h
SRCS = sound.c sound_server.c ccl_sound.c sound_id.c \
unitsound.c libcda.c
flac.c wav.c unitsound.c libcda.c oss_audio.c sdl_audio.c
OBJS = $(addprefix $(OBJDIR), $(SRCS:.c=.$(OE)))

270
src/sound/flac.cpp Normal file
View file

@ -0,0 +1,270 @@
// ___________ _________ _____ __
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
// \/ \/ \/ \/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// FreeCraft - A free fantasy real time strategy game engine
//
/**@name flac.c - flac support */
//
// (c) Copyright 2002 by Lutz Sammer and Fabrice Rossi
//
// FreeCraft 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; only version 2 of the License.
//
// FreeCraft 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.
//
// $Id$
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include "freecraft.h"
#if defined(WITH_SOUND) && defined(USE_FLAC) // {
#include <stdlib.h>
#include "FLAC/stream_decoder.h"
#include "iolib.h"
#include "sound_server.h"
/*----------------------------------------------------------------------------
-- Declaration
----------------------------------------------------------------------------*/
/**
** My user data for flac callbacks.
*/
typedef struct _my_user_ {
CLFile* File; // File handle
Sample* Sample; // Sample buffer
} MyUser;
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** Read callback from FLAC stream decoder.
**
** @param stream Decoder stream.
** @param status Error state.
** @param user User data.
*/
local void FLAC_error_callback(const FLAC__StreamDecoder * stream,
FLAC__StreamDecoderErrorStatus status, void *user)
{
DebugLevel0Fn(" %s\n",FLAC__StreamDecoderErrorStatusString[status]);
}
/**
** Read callback from FLAC stream decoder.
**
** @param stream Decoder stream.
** @param buffer Buffer to be filled.
** @param bytes Number of bytes to be filled.
** @param user User data.
**
** @return Error status.
*/
local FLAC__StreamDecoderReadStatus FLAC_read_callback(const
FLAC__StreamDecoder * stream, FLAC__byte buffer[], unsigned int *bytes,
void *user)
{
int i;
CLFile *f;
DebugLevel3Fn("Read callback %d\n", *bytes);
f = ((MyUser *) user)->File;
if ((i = CLread(f, buffer, *bytes)) != *bytes) {
*bytes = i;
if (!i) {
return FLAC__STREAM_DECODER_READ_END_OF_STREAM;
}
}
return FLAC__STREAM_DECODER_READ_CONTINUE;
}
/**
** Write callback from FLAC stream decoder.
**
** @param stream Decoder stream.
** @param metadata metadata block
** @param user User data.
*/
local void FLAC_metadata_callback(const FLAC__StreamDecoder * stream,
const FLAC__StreamMetaData * metadata, void *user)
{
Sample *sample;
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO) {
sample = ((MyUser *) user)->Sample;
sample->Channels = metadata->data.stream_info.channels;
sample->Frequency = metadata->data.stream_info.sample_rate;
sample->SampleSize = metadata->data.stream_info.bits_per_sample;
DebugLevel3Fn("Stream %d Channels, %d frequency, %d bits\n",
sample->Channels, sample->Frequency, sample->SampleSize);
}
}
/**
** Write callback from FLAC stream decoder.
**
** @param stream Decoder stream.
** @param buffer Buffer to be filled.
** @param bytes Number of bytes to be filled.
** @param user User data.
**
** @return Error status.
*/
static FLAC__StreamDecoderWriteStatus FLAC_write_callback(const
FLAC__StreamDecoder * stream, const FLAC__Frame * frame,
const FLAC__int32 * buffer[], void *user)
{
Sample *sample;
int i;
int channel;
void *p;
DebugLevel3Fn("Write callback %d bits, %d channel, %d bytes\n",
frame->header.bits_per_sample, frame->header.channels,
frame->header.blocksize);
sample = ((MyUser *) user)->Sample;
DebugCheck(frame->header.bits_per_sample != sample->SampleSize);
i = frame->header.channels * frame->header.blocksize *
frame->header.bits_per_sample / 8;
((MyUser *) user)->Sample = sample =
realloc(sample, sizeof(*sample) + sample->Length + i);
if (!sample) {
fprintf(stderr, "Out of memory!\n");
CLclose(((MyUser *) user)->File);
exit(-1);
}
p = sample->Data + sample->Length;
sample->Length += i;
switch (sample->SampleSize) {
case 8:
for (i = 0; i < frame->header.blocksize; i++) {
for (channel = 0; channel < frame->header.channels; channel++) {
*((unsigned char *)p)++ = buffer[channel][i] + 128;
}
}
break;
case 16:
for (i = 0; i < frame->header.blocksize; i++) {
for (channel = 0; channel < frame->header.channels; channel++) {
*((short *)p)++ = buffer[channel][i];
}
}
break;
default:
fprintf(stderr, "Unsupported sample depth!\n");
CLclose(((MyUser *) user)->File);
exit(-1);
}
return FLAC__STREAM_DECODER_WRITE_CONTINUE;
}
/**
** Load flac.
**
** @param name File name.
**
** @return Returns the loaded sample.
*/
global Sample* LoadFlac(const char* name)
{
MyUser user;
CLFile* f;
Sample* sample;
unsigned long magic;
FLAC__StreamDecoder* stream;
if( !(f=CLopen(name)) ) {
fprintf(stderr,"Can't open file `%s'\n",name);
return NULL;
}
CLread(f,&magic,sizeof(magic));
if( magic!=0x43614C66 ) { // "fLaC" in ASCII
return NULL;
}
DebugLevel2Fn("Have flac file %s\n",name);
// FIXME: ugly way to seek to start of file
CLclose(f);
if( !(f=CLopen(name)) ) {
fprintf(stderr,"Can't open file `%s'\n",name);
return NULL;
}
if( !(stream=FLAC__stream_decoder_new()) ) {
fprintf(stderr,"Can't initialize flac decoder\n");
CLclose(f);
return NULL;
}
FLAC__stream_decoder_set_read_callback(stream, FLAC_read_callback);
FLAC__stream_decoder_set_write_callback(stream, FLAC_write_callback);
FLAC__stream_decoder_set_metadata_callback(stream, FLAC_metadata_callback);
FLAC__stream_decoder_set_error_callback(stream, FLAC_error_callback);
FLAC__stream_decoder_set_client_data(stream, &user);
FLAC__stream_decoder_init(stream);
//
// Read sample
//
user.File=f;
user.Sample=sample=malloc(sizeof(*sample));
sample->Channels=0;
sample->SampleSize=0;
sample->Frequency=0;
sample->Length=0;
#if 0
FLAC__stream_decoder_process_metadata(stream);
if( !sample->Channels || !sample->SampleSize ) {
free(sample);
FLAC__stream_decoder_finish(stream);
FLAC__stream_decoder_delete(stream);
CLclose(f);
return NULL;
}
#endif
FLAC__stream_decoder_process_whole_stream(stream);
FLAC__stream_decoder_finish(stream);
FLAC__stream_decoder_delete(stream);
CLclose(f);
DebugLevel0Fn(" %d\n", user.Sample->Length);
IfDebug( AllocatedSoundMemory+=user.Sample->Length; );
return user.Sample;
}
#endif // } WITH_SOUND && USE_FLAC
//@}

163
src/sound/oss_audio.cpp Normal file
View file

@ -0,0 +1,163 @@
// ___________ _________ _____ __
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
// \/ \/ \/ \/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// FreeCraft - A free fantasy real time strategy game engine
//
/**@name oss_audio.c - Oss hardware support */
//
// (c) Copyright 2002 by Lutz Sammer and Fabrice Rossi
//
// FreeCraft 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; only version 2 of the License.
//
// FreeCraft 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.
//
// $Id$
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include "freecraft.h"
#ifdef WITH_SOUND // {
#ifndef USE_SDLA
#include <unistd.h>
#include <fcntl.h>
#include "sound_server.h"
#ifdef __linux__
# include <sys/ioctl.h>
# include <linux/soundcard.h>
#else
# include <sys/ioctl.h>
# include <machine/soundcard.h>
#endif
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** Initialize sound card hardware part for oss compatible drivers.
**
** @param dev Device name ("/dev/dsp").
** @param freq Sample frequenz (44100,22050,11025 hz).
** @param size Sampe size (8bit, 16bit)
** @param wait Flag, if true wait for sound device to open.
**
** @return True if failure, false if everything ok.
*/
global int InitOssSound(const char* dev,int freq,int size,int wait)
{
int dummy;
//
// Open dsp device, 8bit samples, stereo.
//
if( wait ) {
SoundFildes=open(dev,O_WRONLY);
} else {
SoundFildes=open(dev,O_WRONLY|O_NDELAY);
}
if( SoundFildes==-1 ) {
fprintf(stderr,"Can't open audio device `%s'\n",dev);
return 1;
}
dummy=size;
if( ioctl(SoundFildes,SNDCTL_DSP_SAMPLESIZE,&dummy)==-1 ) {
perror(__FUNCTION__ " ioctl(SNDCTL_DSP_SAMPLESIZE)");
close(SoundFildes);
SoundFildes=-1;
return 1;
}
dummy=1;
if( ioctl(SoundFildes,SNDCTL_DSP_STEREO,&dummy)==-1 ) {
perror(__FUNCTION__ " ioctl(SNDCTL_DSP_STEREO)");
close(SoundFildes);
SoundFildes=-1;
return 1;
}
dummy=freq;
if( ioctl(SoundFildes,SNDCTL_DSP_SPEED,&dummy)==-1 ) {
perror(__FUNCTION__ " ioctl(SNDCTL_DSP_SPEED)");
close(SoundFildes);
SoundFildes=-1;
return 1;
}
//
// 33ms buffer minimum.
//
// FIXME: higher speed more buffers!!
switch( freq ) {
case 11025:
dummy=((8<<16) | 8); // 8 Buffers a 256 Bytes
break;
case 22050:
dummy=((8<<16) | 9); // 8 Buffers a 512 Bytes
break;
default:
DebugLevel0Fn("Unexpected sample frequenze %d\n",freq);
// FALL THROUGH
case 44100:
dummy=((8<<16) | 10); // 8 Buffers a 1024 Bytes
break;
}
if( size==16 ) { // 8 bit
++dummy; // double buffer size
}
DebugLevel0Fn("%d bytes %d ms buffer\n",freq*size/8,
((dummy>>16)*(1<<(dummy&0xFFFF))*1000)/(freq*size/8));
if( ioctl(SoundFildes,SNDCTL_DSP_SETFRAGMENT,&dummy)==-1 ) {
perror(__FUNCTION__);
close(SoundFildes);
SoundFildes=-1;
return 1;
}
#if 0
dummy=4;
if( ioctl(SoundFildes,SNDCTL_DSP_SUBDIVIDE,&dummy)==-1 ) {
perror(__FUNCTION__ " ioctl(SNDCTL_DSP_SUBDIVIDE)");
close(SoundFildes);
SoundFildes=-1;
return;
}
#endif
#ifdef DEBUG
if( ioctl(SoundFildes,SNDCTL_DSP_GETBLKSIZE,&dummy)==-1 ) {
perror(__FUNCTION__ " ioctl(SNDCTL_DSP_GETBLKSIZE)");
close(SoundFildes);
SoundFildes=-1;
return 1;
}
DebugLevel2Fn("DSP block size %d\n",dummy);
DebugLevel2Fn("DSP sample speed %d\n",freq);
#endif
return 0;
}
#endif
#endif // } WITH_SOUND
//@}

91
src/sound/sdl_audio.cpp Normal file
View file

@ -0,0 +1,91 @@
// ___________ _________ _____ __
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
// \/ \/ \/ \/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// FreeCraft - A free fantasy real time strategy game engine
//
/**@name sdl_audio.c - SDL hardware support */
//
// (c) Copyright 2002 by Lutz Sammer and Fabrice Rossi
//
// FreeCraft 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; only version 2 of the License.
//
// FreeCraft 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.
//
// $Id$
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include "freecraft.h"
#ifdef WITH_SOUND // {
#ifdef USE_SDLA
#include "SDL.h"
#include "sound_server.h"
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/// FIXME: move function to here.
extern void FillAudio(void* udata __attribute__((unused)),Uint8* stream,
int len);
/**
** Initialize sound card hardware part with SDL.
**
** @param dev Device name ("/dev/dsp").
** @param freq Sample frequenz (44100,22050,11025 hz).
** @param size Sampe size (8bit, 16bit)
** @param wait Flag, if true wait for sound device to open.
**
** @return True if failure, false if everything ok.
*/
global int InitSdlSound(const char* dev, int freq, int size, int wait)
{
SDL_AudioSpec wanted;
wanted.freq = freq;
if (size == 8) {
wanted.format = AUDIO_U8;
} else if (size == 16) {
wanted.format = AUDIO_S16;
} else {
DebugLevel0Fn("Unexpected sample size %d\n", size);
wanted.format = AUDIO_S16;
}
wanted.channels = 2;
wanted.samples = 2048;
wanted.callback = FillAudio;
wanted.userdata = NULL;
// Open the audio device, forcing the desired format
if (SDL_OpenAudio(&wanted, NULL) < 0) {
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
return -1;
}
SoundFildes = 0;
SDL_PauseAudio(0);
return 0;
}
#endif
#endif // } WITH_SOUND
//@}

View file

@ -26,6 +26,10 @@
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include "freecraft.h"
@ -69,7 +73,6 @@
#include "sound_server.h"
#include "sound.h"
#include "wav.h"
#include "ccl.h"
#ifdef USE_LIBMODPLUG
@ -86,12 +89,15 @@
#include "etlib/hash.h"
#endif
#include "myendian.h"
#ifdef USE_SDLCD
#include <SDL.h>
#endif
extern Sample* LoadFlac(const char* name); /// Load a flac file
extern Sample* LoadWav(const char* name); /// Load a wav file
extern Sample* LoadOgg(const char* name); /// Load a ogg file
extern Sample* LoadMp3(const char* name); /// Load a mp3 file
/*----------------------------------------------------------------------------
-- Defines
----------------------------------------------------------------------------*/
@ -250,15 +256,6 @@ global void PlayMusic(const char* name)
}
#endif
if( PlayingMusic ) {
if( ModFile ) {
ModPlug_Unload(ModFile);
ModFile=NULL;
}
PlayingMusic=0;
}
buffer=malloc(8192);
name=LibraryFileName(name,buffer);
@ -278,6 +275,8 @@ global void PlayMusic(const char* name)
buffer=realloc(buffer,size);
DebugLevel0Fn("%d\n",size);
StopMusic(); // stop music before new music
ModFile=ModPlug_Load(buffer,size);
free(buffer);
@ -401,179 +400,10 @@ global void CDRomCheck(void)
#endif
}
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** Load wav.
**
** @param name File name.
**
** @return Returns the loaded sample.
*/
global Sample* LoadWav(const char* name)
{
CLFile* f;
WavChunk chunk;
WavFMT wavfmt;
unsigned long t;
int i;
Sample* sample;
DebugLevel3("Loading `%s'\n",name);
if( !(f=CLopen(name)) ) {
printf("Can't open file `%s'\n",name);
return NULL;
}
CLread(f,&chunk,sizeof(chunk));
// Convert to native format
chunk.Magic = ConvertLE32(chunk.Magic);
chunk.Length = ConvertLE32(chunk.Length);
DebugLevel3("Magic: $%x\n",chunk.Magic);
DebugLevel3("Length: %d\n",chunk.Length);
if( chunk.Magic!=RIFF ) {
printf("Wrong magic %x (not %x)\n",chunk.Magic,RIFF);
CLclose(f);
return NULL;
}
CLread(f,&t,sizeof(t));
t = ConvertLE32(t);
DebugLevel3("Magic: $%lx\n",t);
if( t!=WAVE ) {
printf("Wrong magic %lx (not %x)\n",t,WAVE);
CLclose(f);
exit(-1);
}
CLread(f,&wavfmt,sizeof(wavfmt));
// Convert to native format
wavfmt.FMTchunk = ConvertLE32(wavfmt.FMTchunk);
wavfmt.FMTlength = ConvertLE32(wavfmt.FMTlength);
wavfmt.Encoding = ConvertLE16(wavfmt.Encoding);
wavfmt.Channels = ConvertLE16(wavfmt.Channels);
wavfmt.Frequency = ConvertLE32(wavfmt.Frequency);
wavfmt.ByteRate = ConvertLE32(wavfmt.ByteRate);
wavfmt.SampleSize = ConvertLE16(wavfmt.SampleSize);
wavfmt.BitsPerSample= ConvertLE16(wavfmt.BitsPerSample);
DebugLevel3("Magic: $%x\n",wavfmt.FMTchunk);
DebugLevel3("Length: %d\n",wavfmt.FMTlength);
if( wavfmt.FMTchunk!=FMT ) {
printf("Wrong magic %x (not %x)\n",wavfmt.FMTchunk,FMT);
CLclose(f);
exit(-1);
}
if( wavfmt.FMTlength!=16 && wavfmt.FMTlength!=18 ) {
DebugLevel2("Encoding\t%d\t",wavfmt.Encoding);
DebugLevel2("Channels\t%d\t",wavfmt.Channels);
DebugLevel2("Frequency\t%d\n",wavfmt.Frequency);
DebugLevel2("Byterate\t%d\t",wavfmt.ByteRate);
DebugLevel2("SampleSize\t%d\t",wavfmt.SampleSize);
DebugLevel2("BitsPerSample\t%d\n",wavfmt.BitsPerSample);
printf("Wrong length %d (not %d)\n",wavfmt.FMTlength,16);
CLclose(f);
exit(-1);
}
if( wavfmt.FMTlength==18 ) {
if( CLread(f,&chunk,2)!=2 ) {
abort();
}
}
DebugLevel3("Encoding\t%d\t",wavfmt.Encoding);
DebugLevel3("Channels\t%d\t",wavfmt.Channels);
DebugLevel3("Frequency\t%d\n",wavfmt.Frequency);
DebugLevel3("Byterate\t%d\t",wavfmt.ByteRate);
DebugLevel3("SampleSize\t%d\t",wavfmt.SampleSize);
DebugLevel3("BitsPerSample\t%d\n",wavfmt.BitsPerSample);
//
// Check if supported
//
if( wavfmt.Encoding!=WAV_PCM_CODE ) {
printf("Unsupported encoding %d\n",wavfmt.Encoding);
CLclose(f);
exit(-1);
}
if( wavfmt.Channels!=WAV_MONO && wavfmt.Channels!=WAV_STEREO ) {
printf("Unsupported channels %d\n",wavfmt.Channels);
CLclose(f);
exit(-1);
}
if( wavfmt.SampleSize!=1 && wavfmt.SampleSize!=2 ) {
printf("Unsupported sample size %d\n",wavfmt.SampleSize);
CLclose(f);
exit(-1);
}
if( wavfmt.BitsPerSample!=8 && wavfmt.BitsPerSample!=16 ) {
printf("Unsupported bits per sample %d\n",wavfmt.BitsPerSample);
CLclose(f);
exit(-1);
}
// FIXME: should check it more. Sample frequence
//
// Read sample
//
sample=malloc(sizeof(*sample));
sample->Channels=wavfmt.Channels;
sample->SampleSize=wavfmt.SampleSize*8;
sample->Frequency=wavfmt.Frequency;
sample->Length=0;
for( ;; ) {
if( (i=CLread(f,&chunk,sizeof(chunk)))!=sizeof(chunk) ) {
// FIXME: have 1 byte remaining, wrong wav or wrong code?
// if( i ) printf("Rest: %d\n",i);
break;
}
chunk.Magic = ConvertLE32(chunk.Magic);
chunk.Length = ConvertLE32(chunk.Length);
DebugLevel3("Magic: $%x\n",chunk.Magic);
DebugLevel3("Length: %d\n",chunk.Length);
if( chunk.Magic!=DATA ) {
// FIXME: cleanup the wav files, remove this junk, and don't support
// FIXME: this!!
DebugLevel3("Wrong magic %x (not %x)\n",chunk.Magic,DATA);
DebugLevel3("Junk at end of file\n");
break;
}
i=chunk.Length;
sample=realloc(sample,sizeof(*sample)+sample->Length+i);
if( !sample ) {
printf("Out of memory!\n");
CLclose(f);
exit(-1);
}
if( CLread(f,sample->Data+sample->Length,i)!=i ) {
printf("Unexpected end of file!\n");
CLclose(f);
free(sample);
exit(-1);
}
sample->Length+=i;
}
CLclose(f);
IfDebug( AllocatedSoundMemory+=sample->Length; );
return sample;
}
/**
** Mix sample to buffer.
**
@ -587,6 +417,8 @@ global Sample* LoadWav(const char* name)
** @param size Size of the output buffer to be filled
**
** @return the number of bytes used to fill buffer
**
** @todo Can mix faster if signed 8 bit buffers are used.
*/
local int MixSampleToStereo32(Sample* sample,int index,unsigned char volume,
int* buffer,int size)
@ -694,7 +526,7 @@ SelectionHandling SelectionHandler={{NULL,0},NULL,0};
#ifdef USE_GLIB
local GHashTable* UnitToChannel;
#else
//local hashtable(int,61) UnitToChannel;
local hashtable(int,61) UnitToChannel;
#endif
@ -740,12 +572,14 @@ local int KeepRequest(SoundRequest* sr) {
}
#else
{
SoundChannel *theChannel=Channels;
const SoundChannel *theChannel;
// slow but working solution: we look for the source in the channels
theChannel=Channels;
for(channel=0;channel<MaxChannels;channel++) {
if ((*theChannel).Command == ChannelPlay
&& (*theChannel).Source.Base==sr->Source.Base
&& (*theChannel).Source.Id==sr->Source.Id) {
&& (*theChannel).Source.Base==sr->Source.Base
&& (*theChannel).Source.Id==sr->Source.Id) {
//FIXME: decision should take into account the sound
return 0;
}
@ -965,7 +799,8 @@ local int FillOneChannel(SoundRequest* sr)
** care of registering sound sources.
//FIXME: is this the correct place to do this?
*/
local void FillChannels(int free_channels,int* discarded,int* started) {
local void FillChannels(int free_channels,int* discarded,int* started)
{
int channel;
SoundRequest* sr;
@ -994,8 +829,9 @@ local void FillChannels(int free_channels,int* discarded,int* started) {
NextSoundRequestOut++;
(*discarded)++;
}
if(NextSoundRequestOut>=MAX_SOUND_REQUESTS)
if(NextSoundRequestOut>=MAX_SOUND_REQUESTS) {
NextSoundRequestOut=0;
}
sr=SoundRequests+NextSoundRequestOut;
}
}
@ -1102,6 +938,11 @@ local Sample* LoadSample(const char* name)
char* buf;
buf = strdcat3(FreeCraftLibPath, "/sounds/", name);
#ifdef USE_FLAC
if( (sample=LoadFlac(buf)) ) {
return sample;
}
#endif
if( !(sample=LoadWav(buf)) ) {
fprintf(stderr,"Can't load the sound `%s'\n",name);
}
@ -1121,10 +962,11 @@ local Sample* LoadSample(const char* name)
** @return the sound unique identifier
**
** @todo FIXME: Must handle the errors better.
** FIXME: Support for more sample files (ogg/flac/mp3).
*/
global SoundId RegisterSound(char *files[], unsigned char number)
global SoundId RegisterSound(char *files[], unsigned number)
{
int i;
unsigned i;
ServerSoundId id;
id = malloc(sizeof(*id));
@ -1133,7 +975,7 @@ global SoundId RegisterSound(char *files[], unsigned char number)
for (i = 0; i < number; i++) {
DebugLevel3("Registering `%s'\n", files[i]);
id->Sound.OneGroup[i] = LoadSample(files[i]);
if ( !id->Sound.OneGroup[i] ) {
if (!id->Sound.OneGroup[i]) {
free(id->Sound.OneGroup);
free(id);
return NO_SOUND;
@ -1143,7 +985,7 @@ global SoundId RegisterSound(char *files[], unsigned char number)
} else { // load an unique sound
DebugLevel3("Registering `%s'\n", files[0]);
id->Sound.OneSound = LoadSample(files[0]);
if ( !id->Sound.OneSound ) {
if (!id->Sound.OneSound) {
free(id);
return NO_SOUND;
}
@ -1153,22 +995,28 @@ global SoundId RegisterSound(char *files[], unsigned char number)
return (SoundId) id;
}
/*
** Create a special sound group with two sounds
/**
** Ask the sound server to put together two sounds to form a special sound.
**
** @param first first part of the group
** @param second second part of the group
**
** @return the special sound unique identifier
*/
global SoundId RegisterTwoGroups(SoundId first,SoundId second) {
global SoundId RegisterTwoGroups(SoundId first, SoundId second)
{
ServerSoundId id;
if(first == NO_SOUND || second == NO_SOUND) {
if (first == NO_SOUND || second == NO_SOUND) {
return NO_SOUND;
}
id=(ServerSoundId)malloc(sizeof(*id));
id->Number=TWO_GROUPS;
id->Sound.TwoGroups=(TwoGroups*)malloc(sizeof(TwoGroups));
id->Sound.TwoGroups->First=first;
id->Sound.TwoGroups->Second=second;
id->Range=MAX_SOUND_RANGE;
return (SoundId)id;
id = (ServerSoundId) malloc(sizeof(*id));
id->Number = TWO_GROUPS;
id->Sound.TwoGroups = (TwoGroups *) malloc(sizeof(TwoGroups));
id->Sound.TwoGroups->First = first;
id->Sound.TwoGroups->Second = second;
id->Range = MAX_SOUND_RANGE;
return (SoundId) id;
}
/*
@ -1181,23 +1029,57 @@ global void SetSoundRange(SoundId sound,unsigned char range) {
}
}
/**
** Mix into buffer.
**
** @param buffer Buffer to be filled with samples. Buffer must be big
** enough.
** @param samples Number of samples.
*/
global void MixIntoBuffer(void* buffer,int samples)
{
int* mixer_buffer;
int free_channels;
int dummy1;
int dummy2;
free_channels=HowManyFree();
FillChannels(free_channels,&dummy1,&dummy2);
// Create empty mixer buffer
mixer_buffer=alloca(samples*sizeof(*mixer_buffer));
// FIXME: can save the memset here, if first channel sets the values
memset(mixer_buffer,0,samples*sizeof(*mixer_buffer));
// Add channels to mixer buffer
MixChannelsToStereo32(mixer_buffer,samples);
// Add music to mixer buffer
MixMusicToStereo32(mixer_buffer,samples);
#if SoundSampleSize==8
ClipMixToStereo8(mixer_buffer,samples,buffer);
#endif
#if SoundSampleSize==16
ClipMixToStereo16(mixer_buffer,samples,buffer);
#endif
}
#ifndef USE_SDLA
/**
** Write buffer to sound card.
*/
global void WriteSound(void)
{
int mixer_buffer[1024];
#if SoundSampleSize==8
char buffer[1024];
#endif
#if SoundSampleSize==16
short buffer[1024];
#endif
int free_channels,dummy1,dummy2;
// ARI: If DSP open had failed: No soundcard, other user, etc..
if (SoundFildes == -1) {
DebugLevel0Fn("Shouldn't be reached\n");
return;
}
@ -1207,23 +1089,13 @@ global void WriteSound(void)
audio_buf_info info;
ioctl(SoundFildes,SNDCTL_DSP_GETOSPACE,&info);
DebugLevel0("Free bytes %d\n",info.bytes);
DebugLevel0("%d Free bytes %d\n",FrameCounter,info.bytes);
if( info.bytes<sizeof(buffer) ) {
return;
}
}
free_channels=HowManyFree();
FillChannels(free_channels,&dummy1,&dummy2);
memset(mixer_buffer,0,sizeof(mixer_buffer));
MixChannelsToStereo32(mixer_buffer,sizeof(mixer_buffer)/sizeof(int));
MixMusicToStereo32(mixer_buffer,sizeof(mixer_buffer)/sizeof(int));
#if SoundSampleSize==8
ClipMixToStereo8(mixer_buffer,sizeof(mixer_buffer)/sizeof(int),buffer);
#endif
#if SoundSampleSize==16
ClipMixToStereo16(mixer_buffer,sizeof(mixer_buffer)/sizeof(int),buffer);
#endif
MixIntoBuffer(buffer,sizeof(buffer)/sizeof(*buffer));
while( write(SoundFildes,buffer,sizeof(buffer))==-1 ) {
switch( errno ) {
@ -1252,32 +1124,14 @@ global void WriteSound(void)
** @param stream pointer to buffer you want to fill with information.
** @param len is length of audio buffer in bytes.
*/
local void FillAudio(void* udata __attribute__((unused)),Uint8* stream,int len)
global void FillAudio(void* udata __attribute__((unused)),Uint8* stream,int len)
{
int* mixer_buffer;
int dummy1,dummy2;
#if SoundSampleSize==16
len>>=1;
#endif
mixer_buffer=alloca(len*sizeof(*mixer_buffer));
DebugLevel3Fn("%d\n",len);
FillChannels(HowManyFree(),&dummy1,&dummy2);
// FIXME: can save the memset here, if one channel sets the values
memset(mixer_buffer,0,sizeof(*mixer_buffer)*len);
MixChannelsToStereo32(mixer_buffer,len);
MixMusicToStereo32(mixer_buffer,len);
#if SoundSampleSize==8
ClipMixToStereo8(mixer_buffer,len,stream);
#endif
#if SoundSampleSize==16
ClipMixToStereo16(mixer_buffer,len,(short*)stream);
#endif
MixIntoBuffer(stream,len);
}
#endif // } USE_SDLA
@ -1303,57 +1157,63 @@ global void WriteSoundThreaded(void)
DebugLevel3Fn("\n");
free_channels=MaxChannels;
how_many_playing=0;
free_channels = MaxChannels;
how_many_playing = 0;
// wait for the first sound to come
sem_wait(&SoundThreadChannelSemaphore);
for(;;) {
if( 0 ) {
audio_buf_info info;
for (;;) {
if (0) {
audio_buf_info info;
ioctl(SoundFildes,SNDCTL_DSP_GETOSPACE,&info);
DebugLevel0("Free bytes %d\n",info.bytes);
}
FillChannels(free_channels,&discarded_request,&started_request);
how_many_playing+=started_request;
new_free_channels=0;
if ( how_many_playing ) {
ioctl(SoundFildes, SNDCTL_DSP_GETOSPACE, &info);
DebugLevel0("Free bytes %d\n", info.bytes);
}
FillChannels(free_channels, &discarded_request, &started_request);
how_many_playing += started_request;
new_free_channels = 0;
if (how_many_playing || PlayingMusic) {
memset(mixer_buffer,0,sizeof(mixer_buffer));
memset(mixer_buffer, 0, sizeof(mixer_buffer));
new_free_channels=MixChannelsToStereo32(mixer_buffer,
sizeof(mixer_buffer)/sizeof(int));
MixMusicToStereo32(mixer_buffer,sizeof(mixer_buffer)/sizeof(int));
if (how_many_playing) {
new_free_channels = MixChannelsToStereo32(mixer_buffer,
sizeof(mixer_buffer) / sizeof(int));
}
MixMusicToStereo32(mixer_buffer,
sizeof(mixer_buffer) / sizeof(int));
#if SoundSampleSize==8
ClipMixToStereo8(mixer_buffer,sizeof(mixer_buffer)/sizeof(int),buffer);
ClipMixToStereo8(mixer_buffer, sizeof(mixer_buffer) / sizeof(int),
buffer);
#endif
#if SoundSampleSize==16
ClipMixToStereo16(mixer_buffer,sizeof(mixer_buffer)/sizeof(int),buffer);
ClipMixToStereo16(mixer_buffer, sizeof(mixer_buffer) / sizeof(int),
buffer);
#endif
while( write(SoundFildes,buffer,sizeof(buffer))==-1 ) {
switch( errno ) {
case EAGAIN:
case EINTR:
continue;
while (write(SoundFildes, buffer, sizeof(buffer)) == -1) {
switch (errno) {
case EAGAIN:
case EINTR:
continue;
}
perror("write");
break;
}
perror("write");
break;
how_many_playing -= new_free_channels;
}
free_channels = MaxChannels - how_many_playing;
DebugLevel3("Channels: %d %d %d\n", free_channels, how_many_playing,
new_free_channels);
new_free_channels += discarded_request;
// decrement semaphore by the number of stopped channels
for (; new_free_channels > 0; new_free_channels--) {
// sem_getvalue(&SoundThreadChannelSemaphore,&tmp);
// DebugLevel3("SoundSemaphore: %d\n",tmp);
sem_wait(&SoundThreadChannelSemaphore);
// sem_getvalue(&SoundThreadChannelSemaphore,&tmp);
// DebugLevel3("SoundSemaphore: %d\n",tmp);
}
how_many_playing-=new_free_channels;
}
free_channels=MaxChannels-how_many_playing;
DebugLevel3("Channels: %d %d %d\n",free_channels,how_many_playing,new_free_channels);
new_free_channels+=discarded_request;
// decrement semaphore by the number of stopped channels
for(;new_free_channels>0;new_free_channels--) {
// sem_getvalue(&SoundThreadChannelSemaphore,&tmp);
// DebugLevel3("SoundSemaphore: %d\n",tmp);
sem_wait(&SoundThreadChannelSemaphore);
// sem_getvalue(&SoundThreadChannelSemaphore,&tmp);
// DebugLevel3("SoundSemaphore: %d\n",tmp);
}
}
}
@ -1367,97 +1227,25 @@ global int InitSound(void)
int dummy;
#ifdef USE_SDLA
{
SDL_AudioSpec wanted;
wanted.freq=SoundFrequency;
if( SoundSampleSize==8 ) {
wanted.format=AUDIO_U8;
} else if( SoundSampleSize==16 ) {
wanted.format=AUDIO_S16;
}
wanted.channels=2;
#if SoundSampleSize==8
wanted.samples=2048;
#endif
#if SoundSampleSize==16
wanted.samples=2048;
#endif
wanted.callback=FillAudio;
wanted.userdata=NULL;
// Open the audio device, forcing the desired format
if ( SDL_OpenAudio(&wanted, NULL) < 0 ) {
fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError());
return -1;
}
SoundFildes=0;
SDL_PauseAudio(0);
//
// Open sound device, 8bit samples, stereo.
//
if( InitSdlSound(SoundDeviceName,SoundFrequency,SoundSampleSize,
WaitForSoundDevice) ) {
return 1;
}
#else
//
// Open dsp device, 8bit samples, stereo.
//
//SoundFildes=open(SoundDeviceName,O_WRONLY|O_NDELAY);
SoundFildes=open(SoundDeviceName,O_WRONLY);
if( SoundFildes==-1 ) {
printf("Can't open audio device `%s'\n",SoundDeviceName);
if( InitOssSound(SoundDeviceName,SoundFrequency,SoundSampleSize,
WaitForSoundDevice) ) {
return 1;
}
dummy=SoundSampleSize;
if( ioctl(SoundFildes,SNDCTL_DSP_SAMPLESIZE,&dummy)==-1 ) {
perror(__FUNCTION__);
close(SoundFildes);
SoundFildes=-1;
return 1;
}
dummy=1;
if( ioctl(SoundFildes,SNDCTL_DSP_STEREO,&dummy)==-1 ) {
perror(__FUNCTION__);
close(SoundFildes);
SoundFildes=-1;
return 1;
}
dummy=SoundFrequency;
if( ioctl(SoundFildes,SNDCTL_DSP_SPEED,&dummy)==-1 ) {
perror(__FUNCTION__);
close(SoundFildes);
SoundFildes=-1;
return 1;
}
#if SoundSampleSize==8
dummy=((8<<16) | 10); /* 8 Buffers a 1024 Bytes */
#endif
#if SoundSampleSize==16
dummy=((8<<16) | 11); /* 8 Buffers a 2048 Bytes */
#endif
// FIXME: higher speed more buffers!!
if( ioctl(SoundFildes,SNDCTL_DSP_SETFRAGMENT,&dummy)==-1 ) {
perror(__FUNCTION__);
close(SoundFildes);
SoundFildes=-1;
return 1;
}
#if 0
dummy=4;
if( ioctl(SoundFildes,SNDCTL_DSP_SUBDIVIDE,&dummy)==-1 ) {
perror(__FUNCTION__);
close(SoundFildes);
SoundFildes=-1;
return;
}
#endif
if( ioctl(SoundFildes,SNDCTL_DSP_GETBLKSIZE,&dummy)==-1 ) {
perror(__FUNCTION__);
close(SoundFildes);
SoundFildes=-1;
return 1;
}
DebugLevel3("DSP block size %d\n",dummy);
DebugLevel3("DSP sample speed %d\n",SoundFrequency);
#endif // USE_SDLA
// ARI: the following must be done here to allow sound to work in pre-start menus!
// ARI: The following must be done here to allow sound to work in
// pre-start menus!
// initialize channels
for(dummy=0;dummy<MaxChannels; ++dummy) {
Channels[dummy].Point=dummy+1;
@ -1479,7 +1267,7 @@ global int InitSound(void)
/**
** Initialize sound server structures (and thread)
*/
global int InitSoundServer()
global int InitSoundServer(void)
{
//FIXME: Valid only in shared memory context!
DistanceSilent=3*max(MapWidth,MapHeight);
@ -1546,4 +1334,6 @@ global void QuitSound(void)
#endif // } WITH_SOUND
global int WaitForSoundDevice; /// Block until sound device available
//@}

225
src/sound/wav.cpp Normal file
View file

@ -0,0 +1,225 @@
// ___________ _________ _____ __
// \_ _____/______ ____ ____ \_ ___ \____________ _/ ____\/ |_
// | __) \_ __ \_/ __ \_/ __ \/ \ \/\_ __ \__ \\ __\\ __\
// | \ | | \/\ ___/\ ___/\ \____| | \// __ \| | | |
// \___ / |__| \___ >\___ >\______ /|__| (____ /__| |__|
// \/ \/ \/ \/ \/
// ______________________ ______________________
// T H E W A R B E G I N S
// FreeCraft - A free fantasy real time strategy game engine
//
/**@name wav.c - wav support */
//
// (c) Copyright 2002 by Lutz Sammer and Fabrice Rossi
//
// FreeCraft 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; only version 2 of the License.
//
// FreeCraft 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.
//
// $Id$
//@{
/*----------------------------------------------------------------------------
-- Includes
----------------------------------------------------------------------------*/
#include <stdio.h>
#include "freecraft.h"
#if defined(WITH_SOUND) // {
#include <stdlib.h>
#include "myendian.h"
#include "iolib.h"
#include "sound_server.h"
#include "wav.h"
/*----------------------------------------------------------------------------
-- Declaration
----------------------------------------------------------------------------*/
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
/**
** Load wav.
**
** @param name File name.
**
** @return Returns the loaded sample.
**
** @note A second wav loader is in libmodplug!
*/
global Sample* LoadWav(const char* name)
{
CLFile* f;
WavChunk chunk;
WavFMT wavfmt;
unsigned long t;
int i;
Sample* sample;
DebugLevel3("Loading `%s'\n", name);
if (!(f = CLopen(name))) {
printf("Can't open file `%s'\n", name);
return NULL;
}
CLread(f, &chunk, sizeof(chunk));
// Convert to native format
chunk.Magic = ConvertLE32(chunk.Magic);
chunk.Length = ConvertLE32(chunk.Length);
DebugLevel3("Magic: $%x\n", chunk.Magic);
DebugLevel3("Length: %d\n", chunk.Length);
if (chunk.Magic != RIFF) {
printf("Wrong magic %x (not %x)\n", chunk.Magic, RIFF);
CLclose(f);
return NULL;
}
CLread(f, &t, sizeof(t));
t = ConvertLE32(t);
DebugLevel3("Magic: $%lx\n", t);
if (t != WAVE) {
printf("Wrong magic %lx (not %x)\n", t, WAVE);
CLclose(f);
exit(-1);
}
CLread(f, &wavfmt, sizeof(wavfmt));
// Convert to native format
wavfmt.FMTchunk = ConvertLE32(wavfmt.FMTchunk);
wavfmt.FMTlength = ConvertLE32(wavfmt.FMTlength);
wavfmt.Encoding = ConvertLE16(wavfmt.Encoding);
wavfmt.Channels = ConvertLE16(wavfmt.Channels);
wavfmt.Frequency = ConvertLE32(wavfmt.Frequency);
wavfmt.ByteRate = ConvertLE32(wavfmt.ByteRate);
wavfmt.SampleSize = ConvertLE16(wavfmt.SampleSize);
wavfmt.BitsPerSample = ConvertLE16(wavfmt.BitsPerSample);
DebugLevel3("Magic: $%x\n", wavfmt.FMTchunk);
DebugLevel3("Length: %d\n", wavfmt.FMTlength);
if (wavfmt.FMTchunk != FMT) {
printf("Wrong magic %x (not %x)\n", wavfmt.FMTchunk, FMT);
CLclose(f);
exit(-1);
}
if (wavfmt.FMTlength != 16 && wavfmt.FMTlength != 18) {
DebugLevel2("Encoding\t%d\t", wavfmt.Encoding);
DebugLevel2("Channels\t%d\t", wavfmt.Channels);
DebugLevel2("Frequency\t%d\n", wavfmt.Frequency);
DebugLevel2("Byterate\t%d\t", wavfmt.ByteRate);
DebugLevel2("SampleSize\t%d\t", wavfmt.SampleSize);
DebugLevel2("BitsPerSample\t%d\n", wavfmt.BitsPerSample);
printf("Wrong length %d (not %d)\n", wavfmt.FMTlength, 16);
CLclose(f);
exit(-1);
}
if (wavfmt.FMTlength == 18) {
if (CLread(f, &chunk, 2) != 2) {
abort();
}
}
DebugLevel3("Encoding\t%d\t", wavfmt.Encoding);
DebugLevel3("Channels\t%d\t", wavfmt.Channels);
DebugLevel3("Frequency\t%d\n", wavfmt.Frequency);
DebugLevel3("Byterate\t%d\t", wavfmt.ByteRate);
DebugLevel3("SampleSize\t%d\t", wavfmt.SampleSize);
DebugLevel3("BitsPerSample\t%d\n", wavfmt.BitsPerSample);
//
// Check if supported
//
if (wavfmt.Encoding != WAV_PCM_CODE) {
printf("Unsupported encoding %d\n", wavfmt.Encoding);
CLclose(f);
exit(-1);
}
if (wavfmt.Channels != WAV_MONO && wavfmt.Channels != WAV_STEREO) {
printf("Unsupported channels %d\n", wavfmt.Channels);
CLclose(f);
exit(-1);
}
if (wavfmt.SampleSize != 1 && wavfmt.SampleSize != 2) {
printf("Unsupported sample size %d\n", wavfmt.SampleSize);
CLclose(f);
exit(-1);
}
if (wavfmt.BitsPerSample != 8 && wavfmt.BitsPerSample != 16) {
printf("Unsupported bits per sample %d\n", wavfmt.BitsPerSample);
CLclose(f);
exit(-1);
}
// FIXME: should check it more. Sample frequence
//
// Read sample
//
sample = malloc(sizeof(*sample));
sample->Channels = wavfmt.Channels;
sample->SampleSize = wavfmt.SampleSize * 8;
sample->Frequency = wavfmt.Frequency;
sample->Length = 0;
for (;;) {
if ((i = CLread(f, &chunk, sizeof(chunk))) != sizeof(chunk)) {
// FIXME: have 1 byte remaining, wrong wav or wrong code?
// if( i ) printf("Rest: %d\n",i);
break;
}
chunk.Magic = ConvertLE32(chunk.Magic);
chunk.Length = ConvertLE32(chunk.Length);
DebugLevel3("Magic: $%x\n", chunk.Magic);
DebugLevel3("Length: %d\n", chunk.Length);
if (chunk.Magic != DATA) {
// FIXME: cleanup the wav files, remove this junk, and don't support
// FIXME: this!!
DebugLevel3("Wrong magic %x (not %x)\n", chunk.Magic, DATA);
DebugLevel3("Junk at end of file\n");
break;
}
i = chunk.Length;
sample = realloc(sample, sizeof(*sample) + sample->Length + i);
if (!sample) {
printf("Out of memory!\n");
CLclose(f);
exit(-1);
}
if (CLread(f, sample->Data + sample->Length, i) != i) {
printf("Unexpected end of file!\n");
CLclose(f);
free(sample);
exit(-1);
}
sample->Length += i;
}
CLclose(f);
IfDebug(AllocatedSoundMemory += sample->Length;
);
return sample;
}
#endif // } WITH_SOUND
//@}

View file

@ -698,6 +698,7 @@ local void Usage(void)
\t-s sleep\tNumber of frames for the AI to sleep before it starts\n\
\t-t factor\tComputer units built time factor\n\
\t-v mode\t\tVideo mode (0=default,1=640x480,2=800x600,\n\
\t-w\t\tWait for sound device (OSS sound driver only)\n\
\t\t\t\t3=1024x768,4=1600x1200)\n\
\t-D\t\tVideo mode depth = pixel per point (for Win32/TNT)\n\
\t-F\t\tFull screen video mode (only supported with SDL)\n\
@ -742,7 +743,7 @@ global int main(int argc,char** argv)
// Parse commandline
//
for( ;; ) {
switch( getopt(argc,argv,"c:d:f:hln:p:P:s:t:v:D:N:FL:S:U:W?") ) {
switch( getopt(argc,argv,"c:d:f:hln:p:P:s:t:v:wD:N:FL:S:U:W?") ) {
case 'c':
CclStartFile=optarg;
continue;
@ -800,6 +801,10 @@ global int main(int argc,char** argv)
}
continue;
case 'w':
WaitForSoundDevice=1;
continue;
case 'L':
NetworkLag=atoi(optarg);
continue;