/** * 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; }
ALsizei alCaptureGetData_EXT( UNUSED(ALvoid* data), UNUSED(ALsizei n), UNUSED(ALenum format), UNUSED(ALuint rate) ) { AL_device *dev; ALuint size; ALuint cid; AL_context *cc; /* get the read device */ cid = _alcCCId; cc = _alcGetContext(cid); if ( cc == NULL ) { return 0; } dev = cc->read_device; if ( (dev->format == format) && (dev->speed == rate) ) { size = _alcDeviceRead(cid, data, n); } else { ALuint samples; void *temp; samples = n / (_al_formatbits(format) / 8); /* Set size to the bytes of raw audio data we need */ size = _al_PCMRatioify(rate, dev->speed, format, dev->format, samples); size *= (_al_formatbits(dev->format) / 8); if ( n > (ALsizei)size ) temp = malloc( n ); else temp = malloc( size ); if ( size > 0 ) { size = _alcDeviceRead(cid, temp, size); temp = _alBufferCanonizeData(dev->format, temp, size, dev->speed, format, rate, &size, AL_TRUE); } else { /* Hmm, zero size in record.. */ memset(temp, 0, n); size = n; } if(temp == NULL) { fprintf(stderr, "could not canonize data\n"); return 0; } memcpy(data, temp, size); free( temp ); } return size; }