/** * $Id$ * * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * 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. The Blender * Foundation also sells licenses for use in proprietary software under * the Blender License. See http://www.blender.org/BL/ for information * about this. * * 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. * * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include #include #include #include #include #ifdef HAVE_CONFIG_H #include #endif #ifndef WIN32 #define __USE_XOPEN /* Needed for swab on linux */ #include #undef __USE_XOPEN #else #include #endif #include "MEM_guardedalloc.h" #include "BLI_blenlib.h" #include "BLI_arithb.h" #include "DNA_object_types.h" #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_sound_types.h" #include "DNA_packedFile_types.h" #include "DNA_userdef_types.h" #include "BKE_utildefines.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_sound.h" #include "BKE_library.h" #include "BKE_packedFile.h" #include "BIF_space.h" #include "BIF_screen.h" #include "BIF_interface.h" #include "BIF_editsound.h" #include "BIF_mywindow.h" #include "BSE_drawipo.h" #include "BSE_headerbuttons.h" #include "blendef.h" #include "mydevice.h" #include "SND_C-api.h" #include "SND_DependKludge.h" #include "SYS_System.h" #include "PIL_time.h" /* this might move to the external header */ void* sound_get_libraryinterface(void); static SND_SceneHandle ghSoundScene=NULL; static SND_AudioDeviceInterfaceHandle ghAudioDeviceInterface=NULL; /* que? why only here? because of the type define? */ bSound *sound_find_sound(char *id_name); void sound_read_wav_data(bSound * sound, PackedFile * pf); void sound_stop_sound(void *object, bSound *sound); void winqreadsoundspace(struct ScrArea *sa, void *spacedata, struct BWinEvent *evt); /* void sound_stop_all_sounds(void); already in BIF_editsound.h */ /* Right. Now for some implementation: */ void winqreadsoundspace(ScrArea *sa, void *spacedata, BWinEvent *evt) { SpaceSound *ssound= spacedata; unsigned short event= evt->event; short val= evt->val; float dx, dy; int doredraw= 0, cfra, first = 0; short mval[2], nr; short mousebut = L_MOUSE; if(curarea->win==0) return; if(val) { if( uiDoBlocks(&curarea->uiblocks, event)!=UI_NOTHING ) event= 0; /* swap mouse buttons based on user preference */ if (U.flag & USER_LMOUSESELECT) { if (event == LEFTMOUSE) { event = RIGHTMOUSE; mousebut = L_MOUSE; } else if (event == RIGHTMOUSE) { event = LEFTMOUSE; mousebut = R_MOUSE; } } switch(event) { case LEFTMOUSE: ssound->flag |= SND_CFRA_NUM; do { getmouseco_areawin(mval); areamouseco_to_ipoco(G.v2d, mval, &dx, &dy); cfra = (int)dx; if(cfra< 1) cfra= 1; if( cfra!=CFRA || first ) { first= 0; CFRA= cfra; update_for_newframe(); force_draw_plus(SPACE_VIEW3D, 1); } else PIL_sleep_ms(30); } while(get_mbut() & mousebut); ssound->flag &= ~SND_CFRA_NUM; doredraw= 1; break; case MIDDLEMOUSE: case WHEELUPMOUSE: case WHEELDOWNMOUSE: view2dmove(event); /* in drawipo.c */ break; case RIGHTMOUSE: nr= pupmenu("Time value%t|Frames %x1|Seconds%x2"); if (nr>0) { if(nr==1) ssound->flag |= SND_DRAWFRAMES; else ssound->flag &= ~SND_DRAWFRAMES; doredraw= 1; } break; case PADPLUSKEY: dx= (float)(0.1154*(G.v2d->cur.xmax-G.v2d->cur.xmin)); G.v2d->cur.xmin+= dx; G.v2d->cur.xmax-= dx; test_view2d(G.v2d, curarea->winx, curarea->winy); doredraw= 1; break; case PADMINUS: dx= (float)(0.15*(G.v2d->cur.xmax-G.v2d->cur.xmin)); G.v2d->cur.xmin-= dx; G.v2d->cur.xmax+= dx; test_view2d(G.v2d, curarea->winx, curarea->winy); doredraw= 1; break; case HOMEKEY: do_sound_buttons(B_SOUNDHOME); break; } } if(doredraw) scrarea_queue_winredraw(curarea); } void sound_initialize_sounds(void) { bSound* sound; if(ghSoundScene) { /* clear the soundscene */ SND_RemoveAllSounds(ghSoundScene); SND_RemoveAllSamples(ghSoundScene); } /* initialize sample blocks (doesnt call audio system, needs to be done once after load */ sound = G.main->sound.first; while (sound) { sound_sample_is_null(sound); sound = (bSound *) sound->id.next; } } bSound* sound_make_copy(bSound* originalsound) { bSound* sound = NULL; char name[160]; int len; if(ghSoundScene==NULL) sound_init_audio(); /* only copy sounds that are sounds */ if (originalsound) { /* do some name magic */ strcpy(name, originalsound->name); len = strlen(name); while ((len > 0) && (name[len - 1] != '/') && (name[len - 1] != '\\')) len--; /* allocate the needed memory */ sound = alloc_libblock(&G.main->sound, ID_SO, name + len); /* create a soundobject */ sound->snd_sound = SND_CreateSound(); /* set the samplename */ strcpy(sound->name, name); SND_SetSampleName(sound->snd_sound, sound->name); /* add the new object to the soundscene */ SND_AddSound(ghSoundScene, sound->snd_sound); /* and copy the data from the original */ sound->attenuation = originalsound->attenuation; sound->distance = originalsound->distance; sound->max_gain = originalsound->max_gain; sound->min_gain = originalsound->min_gain; sound->newpackedfile = originalsound->newpackedfile; sound->panning = originalsound->panning; sound->pitch = originalsound->pitch; sound->sample = originalsound->sample; sound->volume = originalsound->volume; if (originalsound->flags & SOUND_FLAGS_3D) sound->flags |= SOUND_FLAGS_3D; else sound->flags &= ~SOUND_FLAGS_3D; } return sound; } void sound_initialize_sample(bSound* sound) { if(ghSoundScene==NULL) sound_init_audio(); if (sound && sound->sample == NULL) sound_sample_is_null(sound); } void sound_read_wav_data(bSound* sound, PackedFile* pf) { int i, temp; short shortbuf, *temps; int longbuf; char buffer[25]; char *data = NULL; char *tempc; bSample *sample = NULL; int channels, rate, bits, len; /* prepare for the worst... */ sound->sample->type = SAMPLE_INVALID; rewindPackedFile(pf); /* check to see if it is a file in "RIFF WAVE fmt" format */ if (readPackedFile(pf, buffer, 16) != 16) { if (G.f & G_DEBUG) printf("File too short\n"); return; } if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8))) { readPackedFile(pf, &i, 4);// start of data if(G.order==B_ENDIAN) SWITCH_INT(i); /* read the sampleformat */ readPackedFile(pf, &shortbuf, 2); if(G.order==B_ENDIAN) { /* was SWITCH_SHORT before */ char s_i, *p_i; p_i= (char *)&(shortbuf); s_i= p_i[0]; p_i[0]= p_i[1]; p_i[1]= s_i; } /* read the number of channels */ readPackedFile(pf, &shortbuf, 2); if(G.order==B_ENDIAN) { /* was SWITCH_SHORT before */ char s_i, *p_i; p_i= (char *)&(shortbuf); s_i= p_i[0]; p_i[0]= p_i[1]; p_i[1]= s_i; } /* check the number of channels */ if(shortbuf != 1 && shortbuf != 2) { if (G.f & G_DEBUG) printf("Unsupported number of channels\n"); return; } channels = shortbuf; /* read the samplerate */ readPackedFile(pf, &longbuf, 4); if(G.order==B_ENDIAN) SWITCH_INT(longbuf); rate = longbuf; /* read the bitrate */ // Ton's way readPackedFile(pf, &temp, 4); if(G.order==B_ENDIAN) SWITCH_INT(temp); if(channels && rate) bits= 8*temp/(rate * channels); // Frank's way readPackedFile(pf, &shortbuf, 2); readPackedFile(pf, &shortbuf, 2); if(G.order==B_ENDIAN) { /* was SWITCH_SHORT before */ char s_i, *p_i; p_i= (char *)&(shortbuf); s_i= p_i[0]; p_i[0]= p_i[1]; p_i[1]= s_i; } bits = shortbuf; seekPackedFile(pf, i-16, SEEK_CUR); readPackedFile(pf, buffer, 4); /* check if we have a 'data' chunk */ while(memcmp(buffer, "data", 4)!=0) { if (readPackedFile(pf, &i, 4) != 4) break; if(G.order==B_ENDIAN) SWITCH_INT(i); seekPackedFile(pf, i, SEEK_CUR); if (readPackedFile(pf, buffer, 4) != 4) break; } /* guess not */ if (memcmp(buffer, "data", 4) !=0) { if (G.f & G_DEBUG) printf("No data found\n"); } /* or maybe we do! */ else { readPackedFile(pf, &longbuf, 4); if(G.order==B_ENDIAN) SWITCH_INT(longbuf); /* handle 8 and 16 bit samples differently */ /* intrr: removed, longbuf is length in bytes, not samples */ if (bits == 16) data = (char *)MEM_mallocN(longbuf, "sample data"); else data = (char *)MEM_mallocN(longbuf*2, "sample data"); len = longbuf /*/ 4.0*/; /* for some strange reason the sample length is off by a factor of 4... */ /* intrr's comment: Funny eh, how one 16-bit stereo sample is 4 bytes? :-) */ if(data) { readPackedFile(pf, data, len); /* data is only used to draw! */ if (bits == 8) { temps = (short *) data; tempc = (char *) data; for (i = len - 1; i >= 0; i--) temps[i] = tempc[i] << 8; } else { if(G.order==B_ENDIAN) { swab(data, data, len); } } /* fill the sound with the found data */ sample = sound->sample; sample->channels = channels; sample->rate = rate; sample->bits = bits; sample->len = len; sample->data = data; sample->type = SAMPLE_WAV; } } } else { sound->sample->type = SAMPLE_INVALID; if (G.f & G_DEBUG) printf("Unsupported sound format: %s\n", sound->name); } } /* ugly, but it works (for now) */ int sound_get_filetype_from_header(bSound* sound, PackedFile* pf) { int filetype = SAMPLE_INVALID; int i; char buffer[25]; short shortbuf; rewindPackedFile(pf); if (readPackedFile(pf, buffer, 16) != 16) { if (G.f & G_DEBUG) printf("File too short\n"); return filetype; } if(!(memcmp(buffer, "RIFF", 4) && memcmp(&(buffer[8]), "WAVEfmt ", 8))) { readPackedFile(pf, &i, 4); if(G.order==B_ENDIAN) SWITCH_INT(i); /* read the sampleformat */ readPackedFile(pf, &shortbuf, 2); if(G.order==B_ENDIAN) { char s_i, *p_i; p_i= (char *)&(shortbuf); s_i= p_i[0]; p_i[0]= p_i[1]; p_i[1]= s_i; } if (shortbuf == SND_WAVE_FORMAT_PCM) { filetype = SAMPLE_WAV; } else /* only fmod supports compressed wav */ #ifdef USE_FMOD { /* and only valid publishers may use compressed wav */ switch (shortbuf) { case SND_WAVE_FORMAT_ADPCM: case SND_WAVE_FORMAT_ALAW: case SND_WAVE_FORMAT_MULAW: case SND_WAVE_FORMAT_DIALOGIC_OKI_ADPCM: case SND_WAVE_FORMAT_CONTROL_RES_VQLPC: case SND_WAVE_FORMAT_GSM_610: case SND_WAVE_FORMAT_MPEG3: filetype = SAMPLE_WAV; break; default: #endif { filetype = SAMPLE_INVALID; if (G.f & G_DEBUG) printf("Unsupported wav compression\n"); } } #ifdef USE_FMOD } } else if (!memcmp(buffer, "OggS", 4)) { filetype = SAMPLE_OGG_VORBIS; } else if ((!memcmp(buffer, "ID3", 3)) || (!memcmp(buffer, "", 2))) { filetype = SAMPLE_MP3; } #endif else { filetype = SAMPLE_INVALID; if (G.f & G_DEBUG) printf("Unsupported sound format: %s\n", sound->name); } return filetype; } int check_filetype(bSound* sound, PackedFile* pf) { // char* pdest; sound->sample->type = SAMPLE_INVALID; /* // parse the name for the extension to see what kind of sample it is pdest = strrchr(sound->sample->name, '.'); // a simple check to see what kind of sample we're dealing with if (stricmp(pdest, ".wav") == 0) sound->sample->type = SAMPLE_WAV; #ifdef USE_FMOD if (stricmp(pdest, ".mp2") == 0) sound->sample->type = SAMPLE_MP2; if (stricmp(pdest, ".mp3") == 0) sound->sample->type = SAMPLE_MP3; if (stricmp(pdest, ".ogg") == 0) sound->sample->type = SAMPLE_OGG_VORBIS; if (stricmp(pdest, ".raw") == 0) sound->sample->type = SAMPLE_RAW; if (stricmp(pdest, ".wma") == 0) sound->sample->type = SAMPLE_WMA; if (stricmp(pdest, ".asf") == 0) sound->sample->type = SAMPLE_ASF; #endif */ sound->sample->type = sound_get_filetype_from_header(sound, pf); /* get some info from the sample */ switch (sound->sample->type) { case SAMPLE_WAV: { sound_read_wav_data(sound, pf); break; } case SAMPLE_OGG_VORBIS: case SAMPLE_MP3: case SAMPLE_MP2: case SAMPLE_RAW: case SAMPLE_WMA: case SAMPLE_ASF: break; default: { if (G.f & G_DEBUG) printf("No valid sample: %s\n", sound->name); break; } } return sound->sample->type; } int sound_load_sample(bSound* sound) { int result = FALSE; PackedFile* pf; int freePF = FALSE; int buffer = -1; if(ghSoundScene==NULL) sound_init_audio(); /* check the sample (valid?) */ if (sound->sample->type == SAMPLE_UNKNOWN || sound->snd_sound == NULL) { /* find... */ pf = sound_find_packedfile(sound); /* ...or create a (temp)packedfile */ if (pf == NULL) { pf = newPackedFile(sound->name); /* if autopack is off, free the pf afterwards */ if ((G.fileflags & G_AUTOPACK) == 0) freePF = TRUE; } /* if we have a valid pf... */ if (pf) { /* check the content of the pf */ check_filetype(sound, pf); /* check if the sampletype is supported */ if (sound->sample->type != SAMPLE_INVALID && sound->sample->type != SAMPLE_UNKNOWN) { /* register the sample at the audiodevice */ buffer = SND_AddSample(ghSoundScene, sound->sample->name, pf->data, pf->size); /* create a soundobject */ sound->snd_sound = SND_CreateSound(); SND_SetSampleName(sound->snd_sound, sound->sample->name); /* add the soundobject to the soundscene */ if (SND_CheckBuffer(ghSoundScene, sound->snd_sound)) SND_AddSound(ghSoundScene, sound->snd_sound); else if (G.f & G_DEBUG) printf("error: sample didn't load properly\n"); /* if it was places in buffer[0] or higher, it succeeded */ if (buffer >= 0) result = TRUE; } /* if not, free the pf */ else { freePF = TRUE; } /* if you want it freed, make it so */ if (freePF) { freePackedFile(pf); pf = NULL; } /* or else connect the pf to the sound and sample */ // else // { sound->newpackedfile = pf; sound->sample->packedfile = pf; // } } else { if (G.f & G_DEBUG) printf("%s: File not found!\n", sound->name); sound->sample->type = SAMPLE_INVALID; } } /* if the sample ain't invalid, we're ready to go! */ else if (sound->sample->type != SAMPLE_INVALID) { result = TRUE; } return result; } bSound* sound_new_sound(char* name) { bSound *sound = NULL; int len, file; char str[FILE_MAXDIR+FILE_MAXFILE]; if(ghSoundScene==NULL) sound_init_audio(); if (!G.scene->audio.mixrate) G.scene->audio.mixrate = 44100; /* convert the name to absolute path */ strcpy(str, name); BLI_convertstringcode(str, G.sce, G.scene->r.cfra); /* check if the sample on disk can be opened */ file = open(str, O_BINARY|O_RDONLY); if (file != -1) { close(file); /* do some name magic */ len = strlen(name); while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\') len--; /* allocate some memory for the sound */ sound = alloc_libblock(&G.main->sound, ID_SO, name + len); strcpy(sound->name, name); /* intialize and check the sample */ sound_initialize_sample(sound); /* load the sample & check if this blender supports the sound format */ // sound_load_sample(sound); if (sound->sample->type == SAMPLE_INVALID) { free_libblock(&G.main->sound, sound); sound = NULL; } else { sound->volume = 1.0; sound->attenuation = 1.0; sound->distance = 1.0; sound->min_gain = 0.0; sound->max_gain = 1.0; } } return (sound); } int sound_set_sample(bSound *sound, bSample *sample) { int result = TRUE; if(ghSoundScene==NULL) sound_init_audio(); /* decrease the usernumber for this sample */ if (sound->sample) sound->sample->id.us--; /* delete the soundobject */ if (sound->snd_sound) { SND_RemoveSound(ghSoundScene, sound->snd_sound); sound->snd_sound = NULL; } /* connect the sample to the sound */ sound->sample = sample; sound->newpackedfile = NULL; /* increase the usercount */ if (sound->sample) { sound->sample->id.us++; /* and set the right pf */ sound->newpackedfile = sample->packedfile; /* if the sampletype is unknown initialize it */ if (sound->sample->type == SAMPLE_UNKNOWN) { sound_initialize_sample(sound); /* load the sample & check if this blender supports the sound format */ if (!sound_load_sample(sound)) { result = FALSE; } } } return result; } bSample *sound_new_sample(bSound * sound) { bSample *sample = NULL; int len; char *name; if (sound != NULL) { name = sound->name; len = strlen(name); /* do some name magic */ while (len > 0 && name[len - 1] != '/' && name[len - 1] != '\\') len--; /* allocate the memory for the sample */ sample = alloc_libblock(samples, ID_SAMPLE, name + len); sample->data = &sample->fakedata[0]; sample->type = SAMPLE_UNKNOWN; /* some default settings. We get divide by zero if these values are not set */ sample->channels = 1; sample->rate = 44100; sample->bits = 16; sample->alindex = SAMPLE_INVALID; /* convert sound->name to abolute filename */ strcpy(sample->name, sound->name); BLI_convertstringcode(sample->name, G.sce, G.scene->r.cfra); /* connect the pf to the sample */ if (sound->newpackedfile) sample->packedfile = sound->newpackedfile; else sample->packedfile = sound_find_packedfile(sound); } return(sample); } /* find a sample that might already be loaded */ bSample* sound_find_sample(bSound* sound) { bSample* sample; char name[FILE_MAXDIR + FILE_MAXFILE]; char samplename[FILE_MAXDIR + FILE_MAXFILE]; // convert sound->name to abolute filename strcpy(name, sound->name); BLI_convertstringcode(name, G.sce, G.scene->r.cfra); /* search through the list of loaded samples */ sample = samples->first; while (sample) { strcpy(samplename, sample->name); BLI_convertstringcode(samplename, G.sce, G.scene->r.cfra); if (strcmp(name, samplename) == 0) { break; } sample = sample->id.next; } return (sample); } int sound_sample_is_null(bSound* sound) { int result = FALSE; bSample* sample; if(ghSoundScene==NULL) sound_init_audio(); /* find the right sample or else create one */ if (sound->sample == NULL) { /* find... */ sample = sound_find_sample(sound); /* or a new one? */ if (sample == NULL) sample = sound_new_sample(sound); if (sound_set_sample(sound, sample)) result = TRUE; } return result; } void sound_stop_all_sounds(void) { #if GAMEBLENDER == 1 if(ghSoundScene) { SND_StopAllSounds(ghSoundScene); SND_Proceed(ghAudioDeviceInterface, ghSoundScene); } #endif } void sound_end_all_sounds(void) { #if GAMEBLENDER == 1 if(ghSoundScene) { sound_stop_all_sounds(); SND_RemoveAllSounds(ghSoundScene); } #endif } void sound_play_sound(bSound* sound) { #if GAMEBLENDER == 1 if(ghSoundScene==NULL) sound_init_audio(); /* first check if we want sound or not */ SND_IsPlaybackWanted(ghSoundScene); /* stop all previous sounds */ SND_StopAllSounds(ghSoundScene); if (sound != NULL && sound->sample != NULL) { /* load the sample if needed */ if (sound_load_sample(sound)) { /* set all kinds of parameters */ SND_SetListenerGain(ghSoundScene, G.listener->gain); SND_SetDopplerFactor(ghSoundScene, G.listener->dopplerfactor); SND_SetDopplerVelocity(ghSoundScene, G.listener->dopplervelocity); SND_SetGain((SND_ObjectHandle)sound->snd_sound, (sound->volume)); SND_SetPitch((SND_ObjectHandle)sound->snd_sound, (exp((sound->pitch / 12.0) * log(2.0)))); if (sound->flags & SOUND_FLAGS_LOOP) { SND_SetLoopMode((SND_ObjectHandle)sound->snd_sound, SND_LOOP_NORMAL); #ifdef SOUND_UNDER_DEVELOPMENT /* SND_SetLoopPoints((SND_ObjectHandle)sound->snd_sound, sound->loopstart, sound->loopend); */ #endif if (sound->flags & SOUND_FLAGS_BIDIRECTIONAL_LOOP) SND_SetLoopMode((SND_ObjectHandle)sound->snd_sound, SND_LOOP_BIDIRECTIONAL); else SND_SetLoopMode((SND_ObjectHandle)sound->snd_sound, SND_LOOP_NORMAL); } else { SND_SetLoopMode((SND_ObjectHandle)sound->snd_sound, SND_LOOP_OFF); } if (sound->flags & SOUND_FLAGS_3D) { SND_SetRollOffFactor((SND_ObjectHandle)sound->snd_sound, sound->attenuation); SND_SetReferenceDistance((SND_ObjectHandle)sound->snd_sound, sound->distance); SND_SetMinimumGain((SND_ObjectHandle)sound->snd_sound, sound->min_gain); SND_SetMaximumGain((SND_ObjectHandle)sound->snd_sound, sound->max_gain); } else { SND_SetRollOffFactor((SND_ObjectHandle)sound->snd_sound, 0); SND_SetReferenceDistance((SND_ObjectHandle)sound->snd_sound, 1); SND_SetMinimumGain((SND_ObjectHandle)sound->snd_sound, 1); SND_SetMaximumGain((SND_ObjectHandle)sound->snd_sound, 1); } if (G.f & G_DEBUG) printf("Set pitch to: %f\n", SND_GetPitch((SND_ObjectHandle)sound->snd_sound)); if (G.f & G_DEBUG) printf("Set gain to: %f\n", SND_GetGain((SND_ObjectHandle)sound->snd_sound)); if (G.f & G_DEBUG) printf("Set looping to: %d\n", SND_GetLoopMode((SND_ObjectHandle)sound->snd_sound)); /* play the sound */ SND_StartSound(ghSoundScene, (SND_ObjectHandle)sound->snd_sound); /* update the device */ SND_Proceed(ghAudioDeviceInterface, ghSoundScene); } } else { if (G.f & G_DEBUG) { printf("uninitialized sound !\n"); if (sound) { printf("sound: %p\n", sound); if (sound->sample) { printf("sample: %p\n", sound->sample); if (sound->snd_sound) printf("hSoundObject: %p\n", sound->snd_sound); } } else { printf("sound == NULL\n"); } } } #endif } bSound *sound_find_sound(char *id_name) { bSound *sound; // look for sound with same *id* name sound = G.main->sound.first; while (sound) { if (strcmp(sound->id.name + 2, id_name) == 0) break; sound = sound->id.next; } return sound; } void sound_init_audio(void) { int noaudio; SYS_SystemHandle hSystem = NULL; if(ghSoundScene==NULL) { hSystem = SYS_GetSystem(); noaudio = SYS_GetCommandLineInt(hSystem,"noaudio",0); if (noaudio)/*(noaudio) intrr: disable game engine audio (openal) */ SND_SetDeviceType(snd_e_dummydevice); ghAudioDeviceInterface = SND_GetAudioDevice(); ghSoundScene = SND_CreateScene(ghAudioDeviceInterface); // also called after read new file, but doesnt work when no audio initialized sound_initialize_sounds(); } } int sound_get_mixrate(void) { return MIXRATE; } void sound_exit_audio(void) { if(ghSoundScene) { SND_DeleteScene(ghSoundScene); SND_ReleaseDevice(); ghSoundScene = NULL; } }