/* * 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; }
/** * 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; }
/* * 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; }