/* * _alcSpeakerMove( ALuint cid ) * * Moves speakers for context named by cid, using listener orientation and * position as modifiers. * * If cid is invalid, set ALC_INVALID_CONTEXT. * * assumes context cid is locked * * FIXME: * please check my math */ void _alcSpeakerMove( ALuint cid ) { AL_context *cc; ALfloat vec[3]; ALfloat *pos; /* listener position */ ALfloat *ori; /* listener orientation */ ALfloat ipos[3]; /* inverse listener position */ ALuint i; ALfloat m[3][3]; ALfloat pm[3]; ALfloat rm[3]; cc = _alcGetContext( cid ); if(cc == NULL) { _alDebug(ALD_CONTEXT, __FILE__, __LINE__, "_alcSpeakerMove: invalid context id %d", cid); _alcSetError( ALC_INVALID_CONTEXT ); return; } pos = cc->listener.position; ori = cc->listener.orientation; _alVectorCrossProduct(vec, ori + 0, ori + 3); _alVectorNormalize(m[0], vec); _alVectorCrossProduct(vec, m[0], ori + 0); _alVectorNormalize(m[1], vec); _alVectorNormalize(m[2], ori + 0); /* reset speaker position */ _alcSpeakerInit(cid); _alVectorInverse( ipos, cc->listener.position ); /* rotate about at and up vectors */ for(i = 0; i < _alcGetNumSpeakers(cid); i++) { _alVectorTranslate(pm, cc->_speaker_pos[i].pos, ipos); _alVecMatrixMulA3(rm, pm, m); _alVectorTranslate(cc->_speaker_pos[i].pos, rm, pos); } _alDebug(ALD_MATH, __FILE__, __LINE__, "SpAdj: l/r [%f|%f|%f] [%f|%f|%f]", cc->_speaker_pos[0].pos[0], cc->_speaker_pos[0].pos[1], cc->_speaker_pos[0].pos[2], cc->_speaker_pos[1].pos[0], cc->_speaker_pos[1].pos[1], cc->_speaker_pos[1].pos[2]); return; }
/* * _alMixPoolDealloc( _alMixPool *mspool, int msindex, * void (*freer_func)(void *)) * * Finalize a _alMixSource, indexed by msindex, using freer_func, * from mspool, marking is as not in use. */ ALboolean _alMixPoolDealloc( _alMixPool *spool, int msindex, void (*freer_func)(void *) ) { _alMixSource *src; if( msindex < 0 ) { return AL_FALSE; } src = _alMixPoolIndex( spool, msindex ); if(src == NULL) { _alDebug(ALD_MIXER, __FILE__, __LINE__, "%d is a bad index", msindex); return AL_FALSE; } if(spool->pool[msindex].inuse == AL_FALSE) { _alDebug(ALD_MIXER, __FILE__, __LINE__, "index %d is not in use", msindex); /* already deleted */ return AL_FALSE; } spool->pool[msindex].inuse = AL_FALSE; freer_func(src); return AL_TRUE; }
void *grab_write_sdl(void) { sdl_info.spec.freq = DEF_SPEED; sdl_info.spec.channels = DEF_CHANNELS; sdl_info.spec.samples = DEF_SAMPLES; sdl_info.spec.size = DEF_SIZE; sdl_info.spec.format = SDL_DEF_FMT; sdl_info.spec.callback = dummy; if(SDL_OpenAudio(&sdl_info.spec, NULL) < 0) { /* maybe we need SDL_Init? */ SDL_Init(SDL_INIT_AUDIO); if(SDL_OpenAudio(&sdl_info.spec, NULL) < 0) { _alDebug(ALD_CONTEXT, __FILE__, __LINE__, "No SDL: %s", SDL_GetError()); return NULL; } } if(ringbuffer != NULL) { free(ringbuffer); } ringbuffersize = 2 * sdl_info.spec.size; ringbuffer = malloc(ringbuffersize); readOffset = 0; writeOffset = 0; _alBlitBuffer = firsttime_sdl_blitbuffer; _alDebug(ALD_CONTEXT, __FILE__, __LINE__, "SDL grab audio ok"); return &sdl_info.spec; }
ALboolean alutLoadWAV( const char *fname, void **wave, ALsizei *format, ALsizei *size, ALsizei *bits, ALsizei *freq ) { ALushort alFmt = 0; ALushort acChan = 0; ALushort acFreq = 0; ALuint acSize = 0; if(ReadWAVFile(fname, wave, &alFmt, &acChan, &acFreq, &acSize) == AL_FALSE) { _alDebug(ALD_CONVERT, __FILE__, __LINE__, "ReadWAVFile failed for %s", fname); return AL_FALSE; } /* set output params */ *format = (ALsizei) alFmt; *freq = (ALsizei) acFreq; *size = (ALsizei) acSize; *bits = (ALsizei) _al_formatbits(alFmt); _alDebug(ALD_CONVERT, __FILE__, __LINE__, "alutLoadWAV %s with [alformat/size/bits/freq] = [0x%x/%d/%d]", fname, *format, *size, *freq); return AL_TRUE; }
/* 0.0 - 2.0 in seconds */ void alReverbDelay_LOKI(ALuint sid, ALfloat param) { AL_source *src; if((param < 0.0) || (param > 2.0)) { /* * For this kludge, the scale is 2 * normalized. */ _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, "alReverbDelay: invalid value %f", param); _alDCSetError(AL_INVALID_VALUE); return; } _alcDCLockContext(); src = _alDCGetSource(sid); if(src == NULL) { _alDebug(ALD_MAXIMUS, __FILE__, __LINE__, "alReverbScale: invalid source id %d", sid); _alDCSetError(AL_INVALID_NAME); return; } src->reverb_delay = param * canon_speed * _alGetChannelsFromFormat(canon_format); src->flags |= ALS_REVERB; _alcDCUnlockContext(); return; }
/* * index2ErrorNo( int index ) * * Returns an al error from a simple index. */ static ALenum index2ErrorNo( int index ) { switch( index ) { case 0: return AL_NO_ERROR; break; case 1: return AL_INVALID_NAME; break; case 2: return AL_ILLEGAL_ENUM; break; case 3: return AL_INVALID_VALUE; break; case 4: return AL_ILLEGAL_COMMAND; break; case 5: return AL_OUT_OF_MEMORY; break; default: _alDebug( ALD_ERROR, __FILE__, __LINE__, "Unknown index : %d", index ); break; } return -1; }
/* * ErrorNo2index( ALenum error_number ) * * Returns a simple index from an al error. */ static int ErrorNo2index( ALenum error_number ) { switch( error_number ) { case AL_NO_ERROR: return 0; break; case AL_INVALID_NAME: return 1; break; case AL_ILLEGAL_ENUM: return 2; break; case AL_INVALID_VALUE: return 3; break; case AL_ILLEGAL_COMMAND: return 4; break; case AL_OUT_OF_MEMORY: return 5; break; default: _alDebug( ALD_ERROR, __FILE__, __LINE__, "Unknown error condition: 0x%x", error_number ); return -1; break; } return -1; }
/* * If sym has type ALRC_STRING, this call populates retstr ( up to len bytes ) * with the value of the string. */ Rcvar rc_tostr0( Rcvar symp, char *retstr, size_t len ) { AL_rctree *sym = (AL_rctree *) symp; static AL_rctree retval; if(sym == NULL) { return NULL; } if(rc_type(sym) != ALRC_STRING) { _alDebug(ALD_CONFIG, __FILE__, __LINE__, "Not a string"); return NULL; } if(len > sym->data.str.len) { len = sym->data.str.len; } memcpy(retstr, sym->data.str.c_str, len); retstr[len] = '\0'; retval = scmtrue; return &retval; }
/* * Sets the attributes for the device from the settings in the device. The * library is free to change the parameters associated with the device, but * until _alcDeviceSet is called, none of the changes are important. * * Returns ALC_FALSE if the setting operation failed. After a call to this * function, the caller should check the members in dev to see what the * actual values set are. */ ALCboolean _alcDeviceSet(AL_device *dev) { _alDebug(ALD_CONTEXT, __FILE__, __LINE__, "requesting device buffer size %d, format 0x%x, speed %d", dev->bufferSizeInBytes, dev->format, dev->speed); if(!dev->ops->setAttributes(dev->privateData, &dev->bufferSizeInBytes, &dev->format, &dev->speed)) { _alDebug(ALD_CONVERT, __FILE__, __LINE__, "alcDeviceSet_ failed"); return ALC_FALSE; } _alDebug(ALD_CONTEXT, __FILE__, __LINE__, "got device buffer size %d, format 0x%x, speed %d", dev->bufferSizeInBytes, dev->format, dev->speed); return ALC_TRUE; }
static ALboolean ReadWAVFile(const char *fname, void **pcmdata, ALushort *rfmt, ALushort *rchan, ALushort *rfreq, ALuint *rsize) { void *data; ALint len; /* length of pcm portion */ void *udata; if((rfmt == NULL) || (rchan == NULL) || (rfreq == NULL)) { /* bad mojo */ return AL_FALSE; } len = _alSlurp(fname, &data); if(len < 0) { /* couldn't slurp audio file */ _alDebug(ALD_CONVERT, __FILE__, __LINE__, "Could not slurp %s", fname); return AL_FALSE; } if(acLoadWAV(data, (ALuint *) &len, &udata, rfmt, rchan, rfreq) == NULL) { _alDebug(ALD_CONVERT, __FILE__, __LINE__, "Could not buffer and convert data"); free(data); return AL_FALSE; } free(data); *rfmt = _al_AC2ALFMT(*rfmt, *rchan); *rsize = len; *pcmdata = udata; _alDebug(ALD_CONVERT, __FILE__, __LINE__, "ReadWAVFile [freq/size/acformat] = [%d/%d/0x%x]", *rfreq, *rsize, *rfmt); return AL_TRUE; }
int _alLockPrintf( const char *msg, const char *fn, int ln ) { static char threadstr[2048]; char blanks[] = " "; int maxlen = 18 - (strlen(fn) + log10(ln)); blanks[maxlen] = '\0'; sprintf(threadstr, "%s[%u]", blanks, tlSelfThread()); return _alDebug(ALD_LOCK, fn, ln, "%s %s", threadstr, msg); }
/* * rc_foreach( Rcvar ls, Rcvar (*op)( Rcvar operand )) * * For each member in ls, apply op to the member. */ void rc_foreach( Rcvar ls, Rcvar (*op)(Rcvar operand) ) { if( rc_type( ls ) != ALRC_CONSCELL ) { _alDebug( ALD_CONFIG, __FILE__, __LINE__, "rc_foreach failed"); return; } op( rc_car(ls) ); rc_foreach( rc_cdr( ls ), op ); return; }
void *grab_write_esd(void) { esd_format_t fmt; int socket; const char *esdkey = genesdkey(); const char *espeaker = getenv("ESPEAKER"); int esd; esd = esd_open_sound(espeaker); if(esd < 0) { fprintf(stderr, "esd open sound failed.\n"); return NULL; } fmt = ESD_STREAM | ESD_PLAY; switch(DEF_CHANNELS) { case 1: fmt |= ESD_MONO; break; case 2: fmt |= ESD_STEREO; break; default: break; } switch(_al_formatbits(DEF_FORMAT)) { case 8: fmt |= ESD_BITS8; break; case 16: fmt |= ESD_BITS16; break; default: break; } socket = esd_play_stream(fmt, DEF_SPEED, espeaker, esdkey); if(socket < 0) { fprintf(stderr, "esd play stream failed.\n"); return NULL; } _alBlitBuffer = esd_blitbuffer; fprintf(stderr, "esd grab audio ok\n"); _alDebug(ALD_CONTEXT, __FILE__, __LINE__, "esd grab audio ok"); esd_info.speed = DEF_SPEED; esd_info.fmt = fmt; esd_info.socket = socket; esd_info.espeaker = espeaker; esd_info.paused = AL_FALSE; esd_info.esdhandle = esd; strncpy(esd_info.name, esdkey, ESD_NAMELEN); return &esd_info; }
/* * _alExit( void ) * * Finalizes things when the last device is deleted. * * FIXME: we can probably clean a lot of this up now that we have * alc{Open,Close}Device. */ void _alExit( void ) { int i; _alDebug( ALD_MAXIMUS, __FILE__, __LINE__, "_alExit called" ); #ifndef NO_THREADING /* we could be sync, so we check mixthread for a valid ID */ if(mixthread != NULL) { time_for_mixer_to_die = AL_TRUE; _alWaitThread( mixthread ); while( time_for_mixer_to_die == AL_TRUE ) { _alMicroSleep(100000); } } #endif /* NO_THREADING */ for(i = 0; i < _ALC_MAX_CHANNELS; i++) { if(f_buffers.data[i] != NULL) { free( f_buffers.data[i] ); f_buffers.data[i] = NULL; } } f_buffers.len = 0; _alDestroyConfig(); _alDestroyExtensions(); _alDestroyExtensionGroups( ); _alDestroyMixer(); _alDestroyFilters(); _alcDestroyAll(); _alDestroyBuffers(); /* buffers after mixer and alc destroy */ /* do builtin extensions destruction */ BUILTIN_EXT_LOKI_FINI; BUILTIN_EXT_MP3_FINI; BUILTIN_EXT_VORBIS_FINI; alDLExit_ (); }
/* * alGenStreamingBuffers_LOKI * * Perform full allocation in buffers[0..n-1]. If full allocation * is not possible, the appropriate error is set and the function * returns. Each buffer id in a sucessful call can be used with * BufferAppendData. * * If n is 0, legal nop. If n < 0, set INVALID_VALUE and nop. * */ void alGenStreamingBuffers_LOKI( ALsizei n, ALuint *buffer) { AL_buffer *buf; int i; if(n == 0) { /* silently return */ return; } if(n < 0) { _alDebug(ALD_BUFFER, __FILE__, __LINE__, "alGenStreamingBuffers_LOKI: invalid n %d\n", n); _alcDCLockContext(); _alDCSetError( AL_INVALID_VALUE ); _alcDCUnlockContext(); return; } /* generate normal buffers */ alGenBuffers( n, buffer ); _alLockBuffer(); for( i = 0; i < n; i++ ) { buf = _alGetBuffer( buffer[i] ); if( buf == NULL ) { /* allocation must have failed */ _alUnlockBuffer(); return; } /* make sure to set the streaming flag */ buf->flags |= ALB_STREAMING; } _alUnlockBuffer(); return; }
void alBufferi_LOKI(ALuint buffer, ALenum param, ALint value) { AL_buffer *buf = NULL; _alLockBuffer(); buf = _alGetBuffer(buffer); if(buf == NULL) { _alUnlockBuffer(); _alDebug(ALD_BUFFER, __FILE__, __LINE__, "buffer id %d is a bad index", buffer); _alDCSetError(AL_INVALID_NAME); return; } switch(param) { case AL_FREQUENCY: buf->frequency = value; break; case AL_BITS: switch(value) { case 8: switch(_alGetChannelsFromFormat(buf->format)) { case 1: buf->format = AL_FORMAT_MONO8; break; case 2: buf->format = AL_FORMAT_STEREO8; break; default: break; } break; case 16: switch(_alGetChannelsFromFormat(buf->format)) { case 1: buf->format = AL_FORMAT_MONO16; break; case 2: buf->format = AL_FORMAT_STEREO16; break; default: break; } break; } break; case AL_CHANNELS: switch(value) { case 1: switch(_alGetBitsFromFormat(buf->format)) { case 8: buf->format = AL_FORMAT_MONO8; break; case 16: buf->format = AL_FORMAT_MONO16; break; default: break; } break; case 2: switch(_alGetBitsFromFormat(buf->format)) { case 8: buf->format = AL_FORMAT_STEREO8; break; case 16: buf->format = AL_FORMAT_STEREO16; break; } break; } break; case AL_SIZE: buf->size = value; break; default: _alDebug(ALD_BUFFER, __FILE__, __LINE__, "alBufferi bad param 0x%x", param); _alDCSetError(AL_INVALID_ENUM); break; } _alUnlockBuffer(); return; }
/* * _alInit( void ) * * _alInit is called when the "first" device is created. If all * devices are deleted, and then one is created, it is called again. * * Returns AL_TRUE unless some weird sort of memory allocation problem occurs, * in which case AL_FALSE is returned. */ ALboolean _alInit( void ) { ALboolean err; ALuint i; _alDebug( ALD_MAXIMUS, __FILE__, __LINE__, "_alInit called" ); alDLInit_ (); _alDetectCPUCaps(); /* set up SIMD FloatMul */ #ifdef HAVE_SSE2 if (_alHaveSSE2()) _alFloatMul = _alFloatMul_SSE2; else #endif /* HAVE_SSE2 */ #ifdef HAVE_MMX if (_alHaveMMX()) _alFloatMul = _alFloatMul_MMX; else #endif /* HAVE_MMX */ _alFloatMul = _alFloatMul_portable; for(i = 0; i < _ALC_MAX_CHANNELS; i++) { f_buffers.data[i] = NULL; } f_buffers.len = 0; /* buffer initializations */ err = _alInitBuffers(); if(err == AL_FALSE) { return AL_FALSE; } if( _alInitMixer() == AL_FALSE ) { return AL_FALSE; } /* extension initilizations */ err = _alInitExtensions(); if(err == AL_FALSE) { _alDestroyBuffers(); return AL_FALSE; } #ifdef BUILTIN_EXT_LOKI /* FIXME: dynamic-ify this */ /* register extension groups */ _alRegisterExtensionGroup( (const ALubyte*) "ALC_LOKI_audio_channel" ); _alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_buffer_data_callback" ); _alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_IMA_ADPCM_format" ); _alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_WAVE_format" ); _alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_play_position" ); _alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_quadriphonic" ); #ifdef ENABLE_EXTENSION_AL_EXT_MP3 _alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_MP3" ); #endif /* ENABLE_EXTENSION_AL_EXT_MP3 */ #ifdef ENABLE_EXTENSION_AL_EXT_VORBIS _alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_vorbis" ); #endif /* ENABLE_EXTENSION_AL_EXT_VORBIS */ #endif /* BUILTIN_EXT_LOKI */ _alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_capture" ); _alRegisterExtensionGroup( (const ALubyte*) "ALC_EXT_capture" ); _alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_offset" ); for(i = 0; exts[i].addr != NULL; i++) { _alRegisterExtension(exts[i].name, exts[i].addr); } /* do builtin extensions initialization */ BUILTIN_EXT_LOKI_INIT; BUILTIN_EXT_MP3_INIT; BUILTIN_EXT_VORBIS_INIT; return AL_TRUE; }
/* * alQueuei( ALuint sid, ALenum param, ALint i1 ) * * Obsolete function. Remove this. */ void alQueuei( ALuint sid, ALenum param, ALint i1 ) { AL_source *src; ALboolean inrange = AL_FALSE; SOURCELOCK(); src = _alDCGetSource(sid); if(src == NULL) { _alDCSetError(AL_INVALID_NAME); SOURCEUNLOCK(); return; } /* * all calls to alQueuei specify either ALboolean parameters, * which means that i1 is either AL_TRUE, AL_FALSE, or * a buffer id. So check for validity of i1 first, and * set error if that's the case. */ switch(param) { case AL_LOOPING: case AL_SOURCE_RELATIVE: inrange = _alCheckRangeb(i1); break; case AL_BUFFER: inrange = alIsBuffer(i1); break; default: /* invalid param, error below. */ break; } if(inrange == AL_FALSE) { _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alQueuei(%d, 0x%x, ...) called with invalid value %d", sid, param, i1); _alDCSetError(AL_INVALID_VALUE); SOURCEUNLOCK(); return; } switch(param) { /* FIXME: add loop count */ case AL_BUFFER: /* Append bid to end */ _alSourceQueueAppend(src, i1); break; default: _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alQueuei: invalid or stubbed source param 0x%x", param); _alDCSetError(AL_ILLEGAL_ENUM); break; } SOURCEUNLOCK(); return; }
/* * _alSourceUnqueueBuffers( ALuint sid, ALsizei n, ALuint *bids ) * * Non locking version of alSourceUnqueueBuffers. * * assumes locked context */ void _alSourceUnqueueBuffers(ALuint sid, ALsizei n, ALuint *bids ) { AL_source *src; ALuint *tempqueue; AL_sourcestate *tempstate; struct dualarray *dualbuffers; /* the source's bid queue */ struct dualarray *dualbids; /* the passer's bids */ int newsize; int i; int j; if(n == 0) { /* legal nop */ return; } if(n < 0) { /* bad n */ _alDCSetError( AL_INVALID_VALUE ); _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceUnqueueBuffers: invalid numBuffers %d", n ); return; } src = _alDCGetSource( sid ); if(src == NULL) { _alDCSetError(AL_INVALID_NAME); return; } if(n >= src->bid_queue.read_index) { /* User has requested too many buffers unqueued */ _alDCSetError( AL_INVALID_VALUE ); _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceUnqueueBuffers: invalid numBuffers %d", n ); return; } dualbuffers = malloc( src->bid_queue.size * sizeof *dualbuffers ); if( dualbuffers == NULL ) { _alDCSetError( AL_OUT_OF_MEMORY ); return; } dualbids = malloc( n * sizeof *dualbuffers ); if( dualbids == NULL ) { free( dualbuffers ); _alDCSetError( AL_OUT_OF_MEMORY ); return; } /* mark */ for( i = 0; i < src->bid_queue.size; i++ ) { dualbuffers[i].id = src->bid_queue.queue[i]; dualbuffers[i].index = i; } for( i = 0; i < n; i++ ) { dualbids[i].id = bids[i]; dualbids[i].index = i; } /* * sort both the source's bids and the passer's deletion * request. */ qsort( dualbuffers, src->bid_queue.size, sizeof *dualbuffers, dualarray_id_cmp ); qsort( dualbids, n, sizeof *dualbids, dualarray_id_cmp ); /* sweep */ newsize = src->bid_queue.size; for( i = 0, j = 0; i < n; i++ ) { if( dualbids[j].id == dualbuffers[i].id ) { dualbuffers[i].id = 0; dualbuffers[i].index = -1; _alBidRemoveQueueRef( dualbids[j].id, src->sid ); j++; newsize--; } } tempqueue = malloc(newsize * sizeof *tempqueue); if(tempqueue == NULL) { /* * ouch */ _alDCSetError( AL_INVALID_VALUE ); free( dualbids ); free( dualbuffers ); return; } tempstate = malloc(newsize * sizeof *tempstate); if(tempstate == NULL) { /* too late * * FIXME: re-add queuerefs removed above */ _alDCSetError(AL_INVALID_VALUE); free( tempqueue ); free( dualbids ); free( dualbuffers ); return; } /* unsort */ qsort( dualbuffers, src->bid_queue.size, sizeof *dualbuffers, dualarray_index_cmp ); /* rewrite */ /* first, skip the 0'd out stuff */ for( i = 0; dualbuffers[i].id == 0; i++ ) { /* * ouch. not sure about read_index or write_index * moving. */ if(src->bid_queue.read_index >= i) { src->bid_queue.read_index--; } if(src->bid_queue.write_index >= i) { src->bid_queue.write_index--; } } for(j = 0; j < newsize; j++, i++) { tempqueue[j] = src->bid_queue.queue[i]; tempstate[j] = src->bid_queue.queuestate[i]; } /* free and assign */ free( dualbuffers ); free( dualbids ); free( src->bid_queue.queue ); free( src->bid_queue.queuestate ); src->bid_queue.queue = tempqueue; src->bid_queue.queuestate = tempstate; src->bid_queue.size = newsize; return; }
/* * alSourceQueueBuffers( ALuint sid, ALsizei numBuffers, ALuint *bids ) * * Queue bids[0..numBuffers-1] to the source named sid, setting * AL_INVALID_VALUE if numBuffers < 0, or AL_INVALID_NAME if either sid or and * bid in bids[0..numBuffers-1] is not a valid buffer. */ void alSourceQueueBuffers( ALuint sid, ALsizei numBuffers, ALuint *bids ) { AL_source *src; ALsizei i; if( numBuffers == 0) { /* with n == 0, we NOP */ return; } if( numBuffers < 0) { _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceQueueBuffers: illegal n value %d\n", numBuffers ); _alcDCLockContext(); _alDCSetError( AL_INVALID_VALUE ); _alcDCUnlockContext(); return; } SOURCELOCK(); src = _alDCGetSource( sid ); if( src == NULL ) { _alDCSetError( AL_INVALID_NAME ); _alDebug(ALD_SOURCE, __FILE__, __LINE__, "alSourceQueueBuffers: invalid sid %d\n", sid ); SOURCEUNLOCK(); return; } _alLockBuffer(); /* make sure that bids are valid */ for( i = 0; i < numBuffers; i++ ) { if( _alIsBuffer( bids[i] ) == AL_FALSE ) { /* * we have an invalid bid. bid 0 is okay but the * rest are not. */ if( bids[i] != 0 ) { _alUnlockBuffer(); _alDCSetError( AL_INVALID_NAME ); SOURCEUNLOCK(); return; } } } /* now, append the bids */ for( i = 0; i < numBuffers; i++ ) { if( bids[i] != 0 ) { /* * only append non-0 bids, because we don't * need them anyway. */ _alSourceQueueAppend( src, bids[i] ); } } /* we're done */ _alUnlockBuffer(); SOURCEUNLOCK(); return; }
/* * Opens a device, using the alrc expression deviceSpecifier to specify * attributes for the device. Returns the device if successful, NULL * otherwise. */ ALCdevice *alcOpenDevice( const ALchar *deviceSpecifier ) { ALCdevice *retval; char dirstr[65]; Rcvar direction = NULL; Rcvar freq_sym = NULL; Rcvar speakers = NULL; Rcvar devices = NULL; int openForInput; if( num_devices == 0 ) { /* first initialization */ if( _alParseConfig() == AL_FALSE ) { _alDebug(ALD_CONFIG, __FILE__, __LINE__, "Couldn't parse config file."); } if( _alInit() == AL_FALSE ) { _alDebug(ALD_CONFIG, __FILE__, __LINE__, "Couldn't initialize OpenAL."); } } /* If the name starts with a ', then it's a device configuration */ if(deviceSpecifier && deviceSpecifier[0] == '\'') { Rcvar listOfLists; /* see if the user defined devices, sampling-rate, or direction */ devices = rc_lookup( "devices" ); direction = rc_lookup( "direction" ); freq_sym = rc_lookup( "sampling-rate" ); speakers = rc_lookup( "speaker-num" ); listOfLists = rc_eval( deviceSpecifier ); rc_foreach( listOfLists, rc_define_list ); /* Got a config, so remove the name from further processing */ deviceSpecifier = NULL; /* redefine the stuff we saved */ if( direction != NULL ) rc_define( "direction", alrc_quote( direction )); if( devices != NULL ) rc_define( "devices", alrc_quote( devices ) ); if( freq_sym != NULL ) rc_define( "sampling-rate", alrc_quote( freq_sym )); if( speakers != NULL ) rc_define( "speaker-num", alrc_quote( speakers )); } direction = rc_lookup( "direction" ); devices = rc_lookup( "devices" ); freq_sym = rc_lookup( "sampling-rate" ); speakers = rc_lookup( "speaker-num" ); memset( dirstr, 0, sizeof(dirstr) ); if( direction != NULL ) { switch( rc_type( direction ) ) { case ALRC_STRING: rc_tostr0(direction, dirstr, 64); break; case ALRC_SYMBOL: rc_symtostr0(direction, dirstr, 64); break; default: break; } } retval = malloc( sizeof *retval ); if( retval == NULL) { /* FIXME: set AL_OUT_OF_MEMORY here? */ return NULL; } /* defaults */ retval->format = _ALC_EXTERNAL_FMT; retval->speed = _ALC_EXTERNAL_SPEED; retval->flags = ALCD_NONE; if( freq_sym != NULL ) { switch(rc_type( freq_sym )) { case ALRC_INTEGER: case ALRC_FLOAT: retval->speed = rc_toint( freq_sym ); break; default: _alDebug(ALD_CONVERT, __FILE__, __LINE__, "invalid type for sampling-rate"); break; } } if( speakers != NULL ) { switch(rc_type( speakers )) { case ALRC_INTEGER: case ALRC_FLOAT: { ALint s = rc_toint( speakers ); if (s >= 0) { ALenum fmt = _al_formatscale( retval->format, (ALuint)s ); if ( fmt >= 0 ) { retval->format = fmt; } } } break; default: break; } } openForInput = (strncmp( dirstr, "read", 64 ) == 0); alcBackendOpen_(deviceSpecifier, (openForInput ? ALC_OPEN_INPUT_ : ALC_OPEN_OUTPUT_), &retval->ops, &retval->privateData ); if( retval->privateData == NULL ) { free( retval ); return NULL; } /* set specifier */ retval->specifier = retval->ops->getName(retval->privateData); retval->flags |= ( openForInput ? ALCD_READ : ALCD_WRITE ); num_devices++; /* Figure out the size of buffer to request from the device based * on the bytes per sample and speed */ retval->bufferSizeInBytes = _alSmallestPowerOfTwo(retval->speed / 15); retval->bufferSizeInBytes *= _alGetChannelsFromFormat(retval->format); retval->bufferSizeInBytes *= _alGetBitsFromFormat(retval->format) / 8; if(_alcDeviceSet(retval) == ALC_FALSE) { alcCloseDevice(retval); return NULL; } return retval; }
/** * * alBufferWriteData_LOKI( ALuint bid, * ALenum format, * ALvoid *data, * ALsizei size, * ALsizei freq * ALenum internalFormat ) * * associates data with bid, with format hint * * If format is invalid, set AL_INVALID_ENUM. If bid is not a valid buffer * name, set AL_INVALID_NAME. If not enough memory is available to make a * copy of this data, set AL_OUT_OF_MEMORY. */ void alBufferWriteData_LOKI( ALuint bid, ALenum format, void *data, ALsizei size, ALsizei freq, ALenum internalFormat ) { AL_buffer *buf; unsigned int retsize; void *cdata; ALuint i; _alLockBuffer(); buf = _alGetBuffer(bid); if(buf == NULL) { _alDebug(ALD_BUFFER, __FILE__, __LINE__, "alBufferData: buffer id %d not valid", bid); _alDCSetError(AL_INVALID_NAME); _alUnlockBuffer(); return; } cdata = _alBufferCanonizeData(format, data, size, freq, internalFormat, buf->frequency, &retsize, AL_FALSE); if(cdata == NULL) { /* _alBufferCanonize Data should set error */ _alUnlockBuffer(); return; } if(buf->flags & ALB_STREAMING) { /* Streaming buffers cannot use alBufferData */ _alDCSetError(AL_INVALID_OPERATION); free(cdata); _alUnlockBuffer(); return; } buf->format = internalFormat; if(buf->size < retsize) { void *temp_copies[_ALC_MAX_CHANNELS] = { NULL }; ALboolean success = AL_TRUE; /* don't use realloc */ _alBufferFreeOrigBuffers(buf); for(i = 0; i < _alGetChannelsFromFormat(buf->format); i++) { temp_copies[i] = malloc(retsize); success = (temp_copies[i] != NULL) ? AL_TRUE : AL_FALSE; } if(!success) { free(cdata); for(i = 0; i < _alGetChannelsFromFormat(buf->format); i++) { free(temp_copies[i]); } /* JIV FIXME: lock context */ _alcDCLockContext(); _alDCSetError(AL_OUT_OF_MEMORY); _alcDCUnlockContext(); _alUnlockBuffer(); return; } switch(_alGetChannelsFromFormat(buf->format)) { case 1: for(i = 0; i < elementsof(buf->orig_buffers); i++) { buf->orig_buffers[i] = temp_copies[0]; } break; case 2: for(i = 0; i < elementsof(buf->orig_buffers); i += 2) { buf->orig_buffers[i] = temp_copies[0]; buf->orig_buffers[i+1] = temp_copies[1]; } break; case 4: assert(elementsof(buf->orig_buffers) >= 4); for(i = 0; i < elementsof(buf->orig_buffers); i += 4) { buf->orig_buffers[i] = temp_copies[0]; buf->orig_buffers[i+1] = temp_copies[1]; buf->orig_buffers[i+2] = temp_copies[2]; buf->orig_buffers[i+3] = temp_copies[3]; } break; case 6: assert(elementsof(buf->orig_buffers) >= 6); for(i = 0; i < elementsof(buf->orig_buffers); i += 6) { buf->orig_buffers[i] = temp_copies[0]; buf->orig_buffers[i+1] = temp_copies[1]; buf->orig_buffers[i+2] = temp_copies[2]; buf->orig_buffers[i+3] = temp_copies[3]; buf->orig_buffers[i+4] = temp_copies[4]; buf->orig_buffers[i+5] = temp_copies[5]; } break; default: /* well this is weird */ assert(0); break; } } _alMonoify((ALshort **) buf->orig_buffers, cdata, retsize / _alGetChannelsFromFormat(buf->format), buf->num_buffers, _alGetChannelsFromFormat(buf->format)); free(cdata); buf->size = retsize / _alGetChannelsFromFormat(buf->format); _alUnlockBuffer(); return; }
/** * Specify data to be filled into a looping buffer. * This takes the current position at the time of the * call, and returns the number of samples written. * * FIXME: this version is not as stingy about memory as * it could be. * * FIXME: move convert to the bottom of the testing, so * that only as much data as is being used will be * converted. * * FIXME: mostly untested * * FIXME: this is the most horrible function ever. I can only * claim responsibility for 50% of the hideous horror that * is this function. Before you smite me to eternal damnation * for the monstrosity that follows, please keep in mind that * the remaining half of the horror belongs squarely on those * who defined the semantics and side effects of this disgusting * monster. * */ ALsizei alBufferAppendData_LOKI( ALuint buffer, ALenum format, void* data, ALsizei osamps, ALsizei freq ) { AL_buffer *buf; ALuint osize; /* old size */ ALuint csize; /* converted size */ ALuint nsamps; /* number of samples that csize represents */ ALuint csamps; /* number of samples to convert */ ALuint psize; /* predicted size of passed data after conversion */ ALuint orig_csamps; /* original number of samples to convert, pre truncation */ unsigned int remainingspace = 0; unsigned int copyoffset = 0; unsigned int copysize = 0; ALenum tformat = 0; /* buffer's target format */ ALuint tfreq = 0; /* buffer's target frequency */ void *temp = NULL; ALuint i; _alLockBuffer(); buf = _alGetBuffer(buffer); if(buf == NULL) { /* invalid buffers go */ _alUnlockBuffer(); _alDebug(ALD_BUFFER, __FILE__, __LINE__, "buffer id %d is invalid", buffer); _alDCSetError(AL_INVALID_NAME); return 0; } /* * Non streaming buffers go bye bye */ if(!(buf->flags & ALB_STREAMING)) { _alUnlockBuffer(); _alDebug(ALD_STREAMING, __FILE__, __LINE__, "buffer id %d not created with alGenStreamingBuffer", buffer); _alDCSetError(AL_INVALID_OPERATION); return 0; } /* initialize stuff */ osize = buf->size; /* * Set csamps to the size of osamps in bytes. * * make sure that csamps contains an even multiple of * the number of channels */ csamps = osamps; csamps -= (csamps % _alGetChannelsFromFormat(format)); csamps *= (_alGetBitsFromFormat(format) / 8); orig_csamps = csamps; /* Set psize to the value that csamps would be in converted format */ psize = _al_PCMRatioify(freq, buf->frequency, format, buf->format, csamps); /* set nsamps */ nsamps = osamps; if(buf->streampos > buf->size) { /* underflow! */ _alDebug(ALD_STREAMING, __FILE__, __LINE__, "underflow! sp|size %d|%d", buf->streampos, buf->size); buf->streampos = buf->appendpos = 0; remainingspace = buf->size; } else if(buf->appendpos > buf->streampos) { remainingspace = buf->size - buf->appendpos; } else if(buf->size != 0) { remainingspace = buf->streampos - buf->appendpos; } else { remainingspace = 0; } if((remainingspace >= MINSTREAMCHUNKSIZE) || (psize <= remainingspace)) { /* only take enough space to fill buffer. */ _alDebug(ALD_STREAMING, __FILE__, __LINE__, "fill data to end: rs|sp|ap. %d|%d|%d", remainingspace, buf->streampos, buf->appendpos); if(remainingspace < psize) { copysize = remainingspace; } else { copysize = psize; } /* scale samples */ nsamps *= copysize; nsamps /= psize; /* remember to set copyoffset for offset_memcpy below */ copyoffset = buf->appendpos; buf->appendpos += copysize; } else if((osize > EXPANDSTREAMBUFSIZE) && (buf->streampos > MINSTREAMCHUNKSIZE) && (buf->appendpos > buf->streampos)) { /* * Okay: * * Since streampos is after append pos, and * streampos is less than the min stream chunk * size, we can safely wrap around and put the * data at the beginning (the WRAP flag gets * removed elsewhere. * * The only thing is, if the buffer is still * fairly small, it would be nice to expand it * so that it can accomodate more data (within * reason). So we check to see if the size * greater than a certain threshold (expandbuffersize), * below which we defer to allow BufferAppendData to * expand the buffer. */ _alDebug(ALD_STREAMING, __FILE__, __LINE__, "reset offset 0 osize|psize|sp|ap|rs %d|%d|%d|%d|%d", osize, psize, buf->streampos, buf->appendpos, remainingspace); if(buf->streampos < psize) { copysize = buf->streampos; } else { copysize = psize; } /* scale samples */ nsamps *= copysize; nsamps /= psize; copyoffset = 0; buf->appendpos = copysize; /* we can wrap. */ buf->flags |= ALB_STREAMING_WRAP; } else if(buf->streampos < buf->appendpos) { unsigned int newsize; _alDebug(ALD_STREAMING, __FILE__, __LINE__, "eb time: size|rs|ap|sp %d|%d|%d|%d", osize, remainingspace, buf->appendpos, buf->streampos); /* we must expand the size of our buffer */ newsize = buf->appendpos + psize; assert(newsize >= osize); for(i = 0; i < buf->num_buffers; i++) { temp = realloc(buf->orig_buffers[i], newsize); if(temp == NULL) { _alUnlockBuffer(); return 0; } buf->orig_buffers[i] = temp; } /* set copy params for offset_memcpy below */ copyoffset = buf->appendpos; copysize = psize; /* reset size */ buf->size = newsize; /* * set append */ buf->appendpos += psize; } else if(buf->size > 0) { /* not ready to accept data */ _alDebug(ALD_STREAMING, __FILE__, __LINE__, "osize|sp|ap|rs %d|%d|%d|%d", osize, buf->streampos, buf->appendpos, remainingspace); _alUnlockBuffer(); return 0; } /* * unlock buffer for time intensive stuff, but * get buffer params first */ tformat = buf->format; tfreq = buf->frequency; _alUnlockBuffer(); /* * Recompute csamps to reflect a decrease of the amount of * data that we will use. */ csamps = nsamps; csamps -= (csamps % _alGetChannelsFromFormat(format)); csamps *= (_alGetBitsFromFormat(format) / 8); /* * We should decide how much data to use such that csize is * a reasonable number. * * bufferAppendScratch = converted data scratch space * csize = converted data's size * * nsamps = number of samples that csize represents */ if(scratch.size < csamps * (_alGetBitsFromFormat(format)/8)) { temp = realloc(scratch.data, csamps * (_alGetBitsFromFormat(format)/8)); if(temp == NULL) { /* oops */ return 0; } scratch.data = temp; scratch.size = csamps * (_alGetBitsFromFormat(format)/8); } memcpy(scratch.data, data, csamps * (_alGetBitsFromFormat(format)>>3)); temp = _alBufferCanonizeData(format, scratch.data, csamps, freq, tformat, tfreq, &csize, AL_TRUE); if(temp == NULL) { /* conversion problem */ _alDCSetError(AL_OUT_OF_MEMORY); _alDebug(ALD_CONVERT, __FILE__, __LINE__, "streaming buffer id %d: could not convert", buffer); return 0; } /* lock buffer again, as we are about to make changes */ _alLockBuffer(); if(buf->size == 0) { /* first time: copy data */ _alDebug(ALD_STREAMING, __FILE__, __LINE__, "first time!"); /* first time */ buf->size = csize / _alGetChannelsFromFormat(buf->format); for(i = 0; i < buf->num_buffers; i++) { temp = realloc(buf->orig_buffers[i], csize / _alGetChannelsFromFormat(buf->format)); if(temp == NULL) { _alUnlockBuffer(); return 0; } buf->orig_buffers[i] = temp; } _alMonoify((ALshort **) buf->orig_buffers, scratch.data, csize / _alGetChannelsFromFormat(buf->format), buf->num_buffers, _alGetChannelsFromFormat(buf->format)); buf->appendpos = csize; _alUnlockBuffer(); return osamps; } _alMonoifyOffset((ALshort **) buf->orig_buffers, copyoffset, scratch.data, csize / _alGetChannelsFromFormat(buf->format), buf->num_buffers, _alGetChannelsFromFormat(buf->format)); /* offset_memcpy(buf->_orig_buffer, copyoffset, bufferAppendScratch, copysize); */ _alUnlockBuffer(); return nsamps; }
/* * _alcSpeakerInit( ALuint cid ) * * Initialize position wrt listener, w/o rt orientation. * * assumes locked context */ static void _alcSpeakerInit( ALuint cid ) { AL_context *cc; AL_listener *lis; ALfloat *lpos; ALfloat sdis; /* scaled distance */ ALuint i; ALuint num; cc = _alcGetContext( cid ); lis = _alcGetListener( cid ); if(cc == NULL) { /* invalid cid */ _alDebug(ALD_CONTEXT, __FILE__, __LINE__, "_alcSpeakerInit: invalid cid 0x%x", cid ); return; } if(lis == NULL) { /* weird */ return; } lpos = lis->position; /* * A speaker distance of one simplifies the math later. */ sdis = 1.0f; _alDebug(ALD_CONTEXT, __FILE__, __LINE__, "_alcSpeakerInit: ( sdis %f )", sdis ); for (i = 0; i < _ALC_MAX_CHANNELS; i++) { cc->_speaker_pos[i].pos[0] = lpos[0]; cc->_speaker_pos[i].pos[1] = lpos[1]; cc->_speaker_pos[i].pos[2] = lpos[2]; } num = _alcGetNumSpeakers(cid); /* fourpoint */ if (num >= 4) { sdis *= M_SQRT1_2; cc->_speaker_pos[ALS_LEFT].pos[2] += sdis; cc->_speaker_pos[ALS_RIGHT].pos[2] += sdis; cc->_speaker_pos[ALS_LEFTS].pos[0] -= sdis; cc->_speaker_pos[ALS_LEFTS].pos[2] -= sdis; cc->_speaker_pos[ALS_RIGHTS].pos[0] += sdis; cc->_speaker_pos[ALS_RIGHTS].pos[2] -= sdis; } /* stereo */ if (num >= 2) { cc->_speaker_pos[ALS_LEFT].pos[0] -= sdis; cc->_speaker_pos[ALS_RIGHT].pos[0] += sdis; } return; }