void alDistanceModel( ALenum distanceModel ) { AL_context *cc = _alcDCGetContext(); if( cc == NULL ) { _alDCSetError( AL_INVALID_OPERATION ); return; } _alcDCLockContext(); switch( distanceModel ) { case AL_NONE: case AL_INVERSE_DISTANCE: case AL_INVERSE_DISTANCE_CLAMPED: case AL_LINEAR_DISTANCE: case AL_LINEAR_DISTANCE_CLAMPED: case AL_EXPONENT_DISTANCE: case AL_EXPONENT_DISTANCE_CLAMPED: cc->distance_model = distanceModel; _alUpdateDistanceModel(cc); break; default: _alDCSetError( AL_INVALID_ENUM ); break; } _alcDCUnlockContext(); }
/* 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; }
const ALchar* alGetString( ALenum param ) { const ALchar *value; static ALchar extensions[1024]; /* TODO: Ugly and not thread-safe! */ AL_context *cc = _alcDCGetContext(); if( cc == NULL ) { _alDCSetError( AL_INVALID_OPERATION ); return NULL; } _alcDCLockContext(); switch (param) { case AL_VERSION: value = "1.1"; break; case AL_RENDERER: value = "OpenAL Sample Implementation"; break; case AL_VENDOR: value = "OpenAL Community"; break; case AL_EXTENSIONS: _alGetExtensionStrings( extensions, sizeof( extensions ) ); value = extensions; break; case AL_NO_ERROR: value = "No Error"; break; case AL_INVALID_NAME: value = "Invalid Name"; break; case AL_INVALID_ENUM: value = "Invalid Enum"; break; case AL_INVALID_VALUE: value = "Invalid Value"; break; case AL_INVALID_OPERATION: value = "Invalid Operation"; break; case AL_OUT_OF_MEMORY: value = "Out of Memory"; break; default: value = NULL; _alDCSetError( AL_INVALID_ENUM ); break; } _alcDCUnlockContext(); return value; }
/* * _alGetDoublev( ALenum param, ALdouble *dv ) * * Non locking version of alGetDoublev * */ void _alGetDoublev(ALenum param, ALdouble *dv) { AL_context *cc; cc = _alcDCGetContext(); if( cc == NULL ) { /* no current context, set error and return */ _alcSetError( ALC_INVALID_CONTEXT ); return; } switch( param ) { case AL_DOPPLER_FACTOR: *dv = cc->doppler_factor; break; case AL_DOPPLER_VELOCITY: *dv = cc->doppler_velocity; break; default: _alDCSetError( AL_ILLEGAL_ENUM ); break; } return; }
/* * _alGetBooleanv( ALenum param, ALboolean *bv) * * Non locking version of alGetBooleanv. */ void _alGetBooleanv(UNUSED(ALenum param), UNUSED(ALboolean *bv)) { _alStub("alGetBooleanv"); /* FIXME: don't set error if no current context */ _alDCSetError( AL_ILLEGAL_ENUM ); return; }
void alDisable( ALenum param ) { AL_context *cc = _alcDCGetContext(); if( cc == NULL ) { _alDCSetError( AL_INVALID_OPERATION ); return; } _alcDCLockContext(); switch (param) { default: _alDCSetError( AL_INVALID_ENUM ); break; } _alcDCUnlockContext(); }
/* * alGetString( ALenum param ) * * Returns readable string representation of param, or NULL if no string * representation is available. */ const ALubyte *alGetString( ALenum param ) { AL_context *cc; static ALubyte extensions[4096]; /* * First, we check to see if the param corresponds to an * error, in which case we return the value from _alGetErrorString. */ if(_alIsError(param) == AL_TRUE) { return _alGetErrorString(param); } /* * Next, we check to see if the param corresponds to an alc * error, in which case we return the value from _alcGetErrorString. */ if( alcIsError( param ) == AL_TRUE ) { return _alcGetErrorString( param ); } switch(param) { case AL_VENDOR: return (const ALubyte *) "J. Valenzuela"; break; case AL_VERSION: return (const ALubyte *) LAL_VERSION; break; case AL_RENDERER: return (const ALubyte *) "Software"; break; case AL_EXTENSIONS: _alGetExtensionStrings( extensions, sizeof( extensions ) ); return extensions; break; case 0xfeedabee: return (const ALubyte *) "Mark 12:31"; break; default: break; } cc = _alcDCGetContext(); if( cc == NULL ) { /* no current context, set error and return */ _alcSetError( ALC_INVALID_CONTEXT ); return NULL; } else { _alDCSetError( AL_ILLEGAL_ENUM ); } return NULL; }
ALboolean alIsEnabled( ALenum param ) { AL_context *cc = _alcDCGetContext(); if( cc == NULL ) { _alDCSetError( AL_INVALID_OPERATION ); return AL_FALSE; } _alcDCLockContext(); switch (param) { default: _alDCSetError( AL_INVALID_ENUM ); break; } _alcDCUnlockContext(); return AL_FALSE; }
void alSpeedOfSound( ALfloat value ) { AL_context *cc = _alcDCGetContext(); if( cc == NULL ) { _alDCSetError( AL_INVALID_OPERATION ); return; } _alcDCLockContext(); if( value <= 0.0f ) { _alDCSetError( AL_INVALID_VALUE ); _alcDCUnlockContext(); return; } cc->speed_of_sound = value; _alcDCUnlockContext(); }
void alDopplerVelocity( ALfloat value ) { AL_context *cc = _alcDCGetContext(); if( cc == NULL ) { _alDCSetError( AL_INVALID_OPERATION ); return; } _alcDCLockContext(); if( value <= 0.0f ) { _alDCSetError( AL_INVALID_VALUE ); _alcDCUnlockContext(); return; } cc->doppler_velocity = value; _alcDCUnlockContext(); }
/* * _alIsEnabled( ALenum param ) * * Non locking version of alIsEnabled. * * assumes locked context */ ALboolean _alIsEnabled( ALenum param ) { AL_context *cc; cc = _alcDCGetContext(); if( cc == NULL ) { return AL_FALSE; } switch( param ) { default: _alDCSetError( AL_ILLEGAL_ENUM ); break; } return AL_FALSE; }
/* * _alDisable( ALenum param ) * * Disables the attribute specified by param. * * If param is not a valid attribute, AL_ILLEGAL_ENUM is set. * * assumes locked context */ void _alDisable( ALenum param ) { AL_context *cc; cc = _alcDCGetContext(); if(cc == NULL) { return; } switch( param ) { default: _alDCSetError( AL_ILLEGAL_ENUM ); break; } return; }
/* * 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; }
/* * Assumes locked context. */ void _alPropagationSpeed(ALfloat value) { AL_context *cc; ALboolean inrange; inrange = _alCheckRangef(value, MIN_PROPAGATION_SPEED, MAX_PROPAGATION_SPEED); if(inrange == AL_FALSE) { _alDCSetError(AL_INVALID_VALUE); return; } cc = _alcDCGetContext(); if(cc == NULL) { return; } cc->propagation_speed = value; return; }
/* * _alGetIntegerv( ALenum param, ALint *iv ) * * Non locking version of alGetIntegerv */ void _alGetIntegerv(UNUSED(ALenum param), UNUSED(ALint *iv)) { AL_context *cc; cc = _alcDCGetContext(); if( cc == NULL ) { /* no current context, set error and return */ _alcSetError( ALC_INVALID_CONTEXT ); return; } switch( param ) { case AL_DISTANCE_MODEL: *iv = cc->distance_model; break; default: _alDCSetError( AL_ILLEGAL_ENUM ); break; } 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; }
/** * * 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; }
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; }
/* * 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; }