This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenkernel/intern/sound.c

466 lines
9.5 KiB
C

/**
* sound.c (mar-2001 nzc)
*
* $Id$
*/
#include <string.h>
#include <stdlib.h>
#include "MEM_guardedalloc.h"
#include "BLI_blenlib.h"
#include "DNA_scene_types.h"
#include "DNA_sound_types.h"
#include "DNA_packedFile_types.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "AUD_C-API.h"
#include "BKE_utildefines.h"
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_sound.h"
#include "BKE_context.h"
#include "BKE_library.h"
#include "BKE_packedFile.h"
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
void sound_init()
{
AUD_Specs specs;
int device, buffersize;
device = U.audiodevice;
buffersize = U.mixbufsize;
specs.channels = U.audiochannels;
specs.format = U.audioformat;
specs.rate = U.audiorate;
if(buffersize < 128)
buffersize = AUD_DEFAULT_BUFFER_SIZE;
if(specs.rate < AUD_RATE_8000)
specs.rate = AUD_RATE_44100;
if(specs.format <= AUD_FORMAT_INVALID)
specs.format = AUD_FORMAT_S16;
if(specs.channels <= AUD_CHANNELS_INVALID)
specs.channels = AUD_CHANNELS_STEREO;
if(!AUD_init(device, specs, buffersize))
AUD_init(AUD_NULL_DEVICE, specs, buffersize);
}
void sound_exit()
{
AUD_exit();
}
struct bSound* sound_new_file(struct Main *main, char* filename)
{
bSound* sound = NULL;
char str[FILE_MAX];
int len;
strcpy(str, filename);
BLI_convertstringcode(str, main->name);
len = strlen(filename);
while(len > 0 && filename[len-1] != '/' && filename[len-1] != '\\')
len--;
sound = alloc_libblock(&main->sound, ID_SO, filename+len);
strcpy(sound->name, filename);
sound->type = SOUND_TYPE_FILE;
sound_load(main, sound);
if(!sound->snd_sound)
{
free_libblock(&main->sound, sound);
sound = NULL;
}
return sound;
}
// XXX unused currently
#if 0
struct bSound* sound_new_buffer(struct bContext *C, struct bSound *source)
{
bSound* sound = NULL;
char name[25];
strcpy(name, "buf_");
strcpy(name + 4, source->id.name);
sound = alloc_libblock(&CTX_data_main(C)->sound, ID_SO, name);
sound->child_sound = source;
sound->type = SOUND_TYPE_BUFFER;
sound_load(CTX_data_main(C), sound);
if(!sound->snd_sound)
{
free_libblock(&CTX_data_main(C)->sound, sound);
sound = NULL;
}
return sound;
}
struct bSound* sound_new_limiter(struct bContext *C, struct bSound *source, float start, float end)
{
bSound* sound = NULL;
char name[25];
strcpy(name, "lim_");
strcpy(name + 4, source->id.name);
sound = alloc_libblock(&CTX_data_main(C)->sound, ID_SO, name);
sound->child_sound = source;
sound->start = start;
sound->end = end;
sound->type = SOUND_TYPE_LIMITER;
sound_load(CTX_data_main(C), sound);
if(!sound->snd_sound)
{
free_libblock(&CTX_data_main(C)->sound, sound);
sound = NULL;
}
return sound;
}
#endif
void sound_delete(struct bContext *C, struct bSound* sound)
{
if(sound)
{
sound_free(sound);
sound_unlink(C, sound);
free_libblock(&CTX_data_main(C)->sound, sound);
}
}
void sound_cache(struct bSound* sound, int ignore)
{
if(sound->cache && !ignore)
AUD_unload(sound->cache);
sound->cache = AUD_bufferSound(sound->snd_sound);
}
void sound_load(struct Main *main, struct bSound* sound)
{
if(sound)
{
if(sound->snd_sound)
{
AUD_unload(sound->snd_sound);
sound->snd_sound = NULL;
}
switch(sound->type)
{
case SOUND_TYPE_FILE:
{
char fullpath[FILE_MAX];
char *path;
/* load sound */
PackedFile* pf = sound->packedfile;
/* dont modify soundact->sound->name, only change a copy */
BLI_strncpy(fullpath, sound->name, sizeof(fullpath));
if(sound->id.lib)
path = sound->id.lib->filename;
else
path = main ? main->name : NULL;
BLI_convertstringcode(fullpath, path);
/* but we need a packed file then */
if (pf)
sound->snd_sound = AUD_loadBuffer((unsigned char*) pf->data, pf->size);
/* or else load it from disk */
else
sound->snd_sound = AUD_load(fullpath);
break;
}
case SOUND_TYPE_BUFFER:
if(sound->child_sound && sound->child_sound->snd_sound)
sound->snd_sound = AUD_bufferSound(sound->child_sound->snd_sound);
break;
case SOUND_TYPE_LIMITER:
if(sound->child_sound && sound->child_sound->snd_sound)
sound->snd_sound = AUD_limitSound(sound->child_sound, sound->start, sound->end);
break;
}
if(sound->cache)
{
}
}
}
void sound_free(struct bSound* sound)
{
if (sound->packedfile)
{
freePackedFile(sound->packedfile);
sound->packedfile = NULL;
}
if(sound->snd_sound)
{
AUD_unload(sound->snd_sound);
sound->snd_sound = NULL;
}
}
void sound_unlink(struct bContext *C, struct bSound* sound)
{
bSound *snd;
Scene *scene;
SoundHandle *handle;
for(snd = CTX_data_main(C)->sound.first; snd; snd = snd->id.next)
{
if(snd->child_sound == sound)
{
snd->child_sound = NULL;
if(snd->snd_sound)
{
AUD_unload(sound->snd_sound);
snd->snd_sound = NULL;
}
sound_unlink(C, snd);
}
}
for(scene = CTX_data_main(C)->scene.first; scene; scene = scene->id.next)
{
for(handle = scene->sound_handles.first; handle; handle = handle->next)
{
if(handle->source == sound)
{
handle->source = NULL;
if(handle->handle)
AUD_stop(handle->handle);
}
}
}
}
struct SoundHandle* sound_new_handle(struct Scene *scene, struct bSound* sound, int startframe, int endframe, int frameskip)
{
ListBase* handles = &scene->sound_handles;
SoundHandle* handle = MEM_callocN(sizeof(SoundHandle), "sound_handle");
handle->source = sound;
handle->startframe = startframe;
handle->endframe = endframe;
handle->frameskip = frameskip;
handle->state = AUD_STATUS_INVALID;
handle->volume = 1.0f;
BLI_addtail(handles, handle);
return handle;
}
void sound_delete_handle(struct Scene *scene, struct SoundHandle *handle)
{
if(handle == NULL)
return;
if(handle->handle)
AUD_stop(handle->handle);
BLI_freelinkN(&scene->sound_handles, handle);
}
void sound_stop_all(struct bContext *C)
{
SoundHandle *handle;
for(handle = CTX_data_scene(C)->sound_handles.first; handle; handle = handle->next)
{
if(handle->state == AUD_STATUS_PLAYING)
{
AUD_pause(handle->handle);
handle->state = AUD_STATUS_PAUSED;
}
}
}
void sound_update_playing(struct bContext *C)
{
SoundHandle *handle;
Scene* scene = CTX_data_scene(C);
int cfra = CFRA;
float fps = FPS;
int action;
AUD_lock();
for(handle = scene->sound_handles.first; handle; handle = handle->next)
{
if(cfra < handle->startframe || cfra >= handle->endframe || handle->mute)
{
if(handle->state == AUD_STATUS_PLAYING)
{
AUD_pause(handle->handle);
handle->state = AUD_STATUS_PAUSED;
}
}
else
{
action = 0;
if(handle->changed != handle->source->changed)
{
handle->changed = handle->source->changed;
action = 3;
if(handle->state != AUD_STATUS_INVALID)
{
AUD_stop(handle->handle);
handle->state = AUD_STATUS_INVALID;
}
}
else
{
if(handle->state != AUD_STATUS_PLAYING)
action = 3;
else
{
handle->state = AUD_getStatus(handle->handle);
if(handle->state != AUD_STATUS_PLAYING)
action = 3;
else
{
float diff = AUD_getPosition(handle->handle) * fps - cfra + handle->startframe;
if(diff < 0.0)
diff = -diff;
if(diff > 1.0f)
{
action = 2;
}
}
}
}
if(action & 1)
{
if(handle->state == AUD_STATUS_INVALID)
{
if(handle->source && handle->source->snd_sound)
{
AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->snd_sound, handle->frameskip / fps, (handle->frameskip + handle->endframe - handle->startframe)/fps);
handle->handle = AUD_play(limiter, 1);
AUD_unload(limiter);
if(handle->handle)
handle->state = AUD_STATUS_PLAYING;
if(cfra == handle->startframe)
action &= ~2;
}
}
else
if(AUD_resume(handle->handle))
handle->state = AUD_STATUS_PLAYING;
else
handle->state = AUD_STATUS_INVALID;
}
if(action & 2)
AUD_seek(handle->handle, (cfra - handle->startframe) / fps);
}
}
AUD_unlock();
}
void sound_scrub(struct bContext *C)
{
SoundHandle *handle;
Scene* scene = CTX_data_scene(C);
int cfra = CFRA;
float fps = FPS;
if(scene->r.audio.flag & AUDIO_SCRUB && !CTX_wm_screen(C)->animtimer)
{
AUD_lock();
for(handle = scene->sound_handles.first; handle; handle = handle->next)
{
if(cfra >= handle->startframe && cfra < handle->endframe && !handle->mute)
{
if(handle->source && handle->source->snd_sound)
{
int frameskip = handle->frameskip + cfra - handle->startframe;
AUD_Sound* limiter = AUD_limitSound(handle->source->cache ? handle->source->cache : handle->source->snd_sound, frameskip / fps, (frameskip + 1)/fps);
AUD_play(limiter, 0);
AUD_unload(limiter);
}
}
}
AUD_unlock();
}
}
AUD_Device* sound_mixdown(struct Scene *scene, AUD_Specs specs, int start, int end)
{
AUD_Device* mixdown = AUD_openReadDevice(specs);
SoundHandle *handle;
float fps = FPS;
AUD_Sound *limiter, *delayer;
int frameskip, s, e;
end++;
for(handle = scene->sound_handles.first; handle; handle = handle->next)
{
if(start < handle->endframe && end > handle->startframe && !handle->mute && handle->source && handle->source->snd_sound)
{
frameskip = handle->frameskip;
s = handle->startframe - start;
e = handle->frameskip + AUD_MIN(handle->endframe, end) - handle->startframe;
if(s < 0)
{
frameskip -= s;
s = 0;
}
limiter = AUD_limitSound(handle->source->snd_sound, frameskip / fps, e / fps);
delayer = AUD_delaySound(limiter, s / fps);
AUD_playDevice(mixdown, delayer);
AUD_unload(delayer);
AUD_unload(limiter);
}
}
return mixdown;
}