/* public */ static void vorbis_stream_decode(struct decoder *decoder, struct input_stream *input_stream) { GError *error = NULL; if (ogg_codec_detect(decoder, input_stream) != OGG_CODEC_VORBIS) return; /* rewind the stream, because ogg_codec_detect() has moved it */ input_stream_lock_seek(input_stream, 0, SEEK_SET, NULL); struct vorbis_input_stream vis; OggVorbis_File vf; if (!vorbis_is_open(&vis, &vf, decoder, input_stream)) return; const vorbis_info *vi = ov_info(&vf, -1); if (vi == NULL) { g_warning("ov_info() has failed"); return; } struct audio_format audio_format; if (!audio_format_init_checked(&audio_format, vi->rate, #ifdef HAVE_TREMOR SAMPLE_FORMAT_S16, #else SAMPLE_FORMAT_FLOAT, #endif vi->channels, &error)) { g_warning("%s", error->message); g_error_free(error); return; } float total_time = ov_time_total(&vf, -1); if (total_time < 0) total_time = 0; decoder_initialized(decoder, &audio_format, vis.seekable, total_time); enum decoder_command cmd = decoder_get_command(decoder); #ifdef HAVE_TREMOR char buffer[4096]; #else float buffer[2048]; const int frames_per_buffer = G_N_ELEMENTS(buffer) / audio_format.channels; const unsigned frame_size = sizeof(buffer[0]) * audio_format.channels; #endif int prev_section = -1; unsigned kbit_rate = 0; do { if (cmd == DECODE_COMMAND_SEEK) { double seek_where = decoder_seek_where(decoder); if (0 == ov_time_seek_page(&vf, seek_where)) { decoder_command_finished(decoder); } else decoder_seek_error(decoder); } int current_section; #ifdef HAVE_TREMOR long nbytes = ov_read(&vf, buffer, sizeof(buffer), VORBIS_BIG_ENDIAN, 2, 1, ¤t_section); #else float **per_channel; long nframes = ov_read_float(&vf, &per_channel, frames_per_buffer, ¤t_section); long nbytes = nframes; if (nframes > 0) { vorbis_interleave(buffer, (const float*const*)per_channel, nframes, audio_format.channels); nbytes *= frame_size; } #endif if (nbytes == OV_HOLE) /* bad packet */ nbytes = 0; else if (nbytes <= 0) /* break on EOF or other error */ break; if (current_section != prev_section) { vi = ov_info(&vf, -1); if (vi == NULL) { g_warning("ov_info() has failed"); break; } if (vi->rate != (long)audio_format.sample_rate || vi->channels != (int)audio_format.channels) { /* we don't support audio format change yet */ g_warning("audio format change, stopping here"); break; } char **comments = ov_comment(&vf, -1)->user_comments; vorbis_send_comments(decoder, input_stream, comments); struct replay_gain_info rgi; if (vorbis_comments_to_replay_gain(&rgi, comments)) decoder_replay_gain(decoder, &rgi); prev_section = current_section; } long test = ov_bitrate_instant(&vf); if (test > 0) kbit_rate = test / 1000; cmd = decoder_data(decoder, input_stream, buffer, nbytes, kbit_rate); } while (cmd != DECODE_COMMAND_STOP); ov_clear(&vf); }
bool AudioBuffer::loadOgg(Stream* stream, ALuint buffer, bool streamed, AudioStreamStateOgg* streamState) { GP_ASSERT(stream); vorbis_info* info; ALenum format; long result; int section; long size = 0; stream->rewind(); ov_callbacks callbacks; callbacks.read_func = readStream; callbacks.seek_func = seekStream; callbacks.close_func = closeStream; callbacks.tell_func = tellStream; if ((result = ov_open_callbacks(stream, &streamState->oggFile, NULL, 0, callbacks)) < 0) { GP_ERROR("Failed to open ogg file."); return false; } info = ov_info(&streamState->oggFile, -1); GP_ASSERT(info); if (info->channels == 1) format = AL_FORMAT_MONO16; else format = AL_FORMAT_STEREO16; // size = #samples * #channels * 2 (for 16 bit). long data_size = ov_pcm_total(&streamState->oggFile, -1) * info->channels * 2; if (streamed) { // Save streaming state for later use. streamState->dataStart = ov_pcm_tell(&streamState->oggFile); streamState->dataSize = data_size; streamState->format = format; streamState->frequency = info->rate; // Limit data size to STREAMING_BUFFER_SIZE. if (data_size > STREAMING_BUFFER_SIZE) data_size = STREAMING_BUFFER_SIZE; } char* data = new char[data_size]; while (size < data_size) { result = ov_read(&streamState->oggFile, data + size, data_size - size, 0, 2, 1, §ion); if (result > 0) { size += result; } else if (result < 0) { SAFE_DELETE_ARRAY(data); GP_ERROR("Failed to read ogg file; file is missing data."); return false; } else { break; } } if (size == 0) { SAFE_DELETE_ARRAY(data); GP_ERROR("Filed to read ogg file; unable to read any data."); return false; } AL_CHECK(alBufferData(buffer, format, data, size, info->rate)); SAFE_DELETE_ARRAY(data); if (!streamed) ov_clear(&streamState->oggFile); return true; }
/* ----------------------------------------------------------------------------- Function: Sound_StreamBGTrack -Called each frame to update streaming music track. Parameters: Nothing Returns: Nothing Notes: ----------------------------------------------------------------------------- */ PUBLIC void Sound_StreamBGTrack( void ) { W8 data[BUFFER_SIZE]; int processed, queued, state; int size, read, dummy; unsigned buffer; if( ! s_musicVolume->value ) { return; } if( ! s_streamingChannel ) { return; } // Unqueue and delete any processed buffers pfalGetSourcei( s_streamingChannel->sourceName, AL_BUFFERS_PROCESSED, &processed ); if( processed > 0 ) { while (processed--) { pfalSourceUnqueueBuffers( s_streamingChannel->sourceName, 1, &buffer ); pfalDeleteBuffers( 1, &buffer ); } } // Make sure we always have at least 4 buffers in the queue pfalGetSourcei( s_streamingChannel->sourceName, AL_BUFFERS_QUEUED, &queued ); while( queued < 4 ) { size = 0; // Stream from disk while( size < BUFFER_SIZE ) { read = ov_read( bgTrack.vorbisFile, (char *)data + size, BUFFER_SIZE - size, &dummy ); if( read == 0 ) { // End of file if( ! bgTrack.looping) { // Close the intro track Sound_CloseBGTrack( &bgTrack ); // Open the loop track if( ! Sound_OpenBGTrack( bgTrack.loopName, &bgTrack ) ) { Sound_StopBGTrack(); return; } bgTrack.looping = true; } // Restart the track, skipping over the header ov_raw_seek( bgTrack.vorbisFile, (ogg_int64_t)bgTrack.start ); // Try streaming again read = ov_read( bgTrack.vorbisFile, (char *)data + size, BUFFER_SIZE - size, &dummy ); } if( read <= 0 ) { // An error occurred Sound_StopBGTrack(); return; } size += read; } // Upload and queue the new buffer pfalGenBuffers( 1, &buffer ); pfalBufferData( buffer, bgTrack.format, data, size, bgTrack.rate ); pfalSourceQueueBuffers( s_streamingChannel->sourceName, 1, &buffer ); queued++; } // Update volume pfalSourcef( s_streamingChannel->sourceName, AL_GAIN, s_musicVolume->value ); // If not playing, then do so pfalGetSourcei( s_streamingChannel->sourceName, AL_SOURCE_STATE, &state ); if( state != AL_PLAYING ) { pfalSourcePlay(s_streamingChannel->sourceName); } }
// // OggResourceLoader::ParseOgg - Chapter 13, page 405 // bool OggResourceLoader::ParseOgg(char *oggStream, size_t length, shared_ptr<ResHandle> handle) { shared_ptr<SoundResourceExtraData> extra = static_pointer_cast<SoundResourceExtraData>(handle->GetExtra()); OggVorbis_File vf; // for the vorbisfile interface ov_callbacks oggCallbacks; OggMemoryFile *vorbisMemoryFile = GCC_NEW OggMemoryFile; vorbisMemoryFile->dataRead = 0; vorbisMemoryFile->dataSize = length; vorbisMemoryFile->dataPtr = (unsigned char *)oggStream; oggCallbacks.read_func = VorbisRead; oggCallbacks.close_func = VorbisClose; oggCallbacks.seek_func = VorbisSeek; oggCallbacks.tell_func = VorbisTell; int ov_ret = ov_open_callbacks(vorbisMemoryFile, &vf, NULL, 0, oggCallbacks); GCC_ASSERT(ov_ret>=0); // ok now the tricky part // the vorbis_info struct keeps the most of the interesting format info vorbis_info *vi = ov_info(&vf,-1); memset(&(extra->m_WavFormatEx), 0, sizeof(extra->m_WavFormatEx)); extra->m_WavFormatEx.cbSize = sizeof(extra->m_WavFormatEx); extra->m_WavFormatEx.nChannels = vi->channels; extra->m_WavFormatEx.wBitsPerSample = 16; // ogg vorbis is always 16 bit extra->m_WavFormatEx.nSamplesPerSec = vi->rate; extra->m_WavFormatEx.nAvgBytesPerSec = extra->m_WavFormatEx.nSamplesPerSec*extra->m_WavFormatEx.nChannels*2; extra->m_WavFormatEx.nBlockAlign = 2*extra->m_WavFormatEx.nChannels; extra->m_WavFormatEx.wFormatTag = 1; DWORD size = 4096 * 16; DWORD pos = 0; int sec = 0; int ret = 1; DWORD bytes = (DWORD)ov_pcm_total(&vf, -1); bytes *= 2 * vi->channels; if (handle->Size() != bytes) { GCC_ASSERT(0 && _T("The Ogg size does not match the memory buffer size!")); ov_clear(&vf); SAFE_DELETE(vorbisMemoryFile); return false; } // now read in the bits while(ret && pos<bytes) { ret = ov_read(&vf, handle->WritableBuffer()+pos, size, 0, 2, 1, &sec); pos += ret; if (bytes - pos < size) { size = bytes - pos; } } extra->m_LengthMilli = (int)(1000.f * ov_time_total(&vf, -1)); ov_clear(&vf); SAFE_DELETE(vorbisMemoryFile); return true; }
bool SoundBuffer::LoadVorbis(const std::string& file, std::vector<boost::uint8_t> buffer, bool strict) { VorbisInputBuffer buf; buf.data = &buffer[0]; buf.pos = 0; buf.size = buffer.size(); ov_callbacks vorbisCallbacks; vorbisCallbacks.read_func = VorbisRead; vorbisCallbacks.close_func = VorbisClose; vorbisCallbacks.seek_func = NULL; vorbisCallbacks.tell_func = NULL; OggVorbis_File oggStream; const int result = ov_open_callbacks(&buf, &oggStream, NULL, 0, vorbisCallbacks); if (result < 0) { LOG_L(L_WARNING, "Could not open Ogg stream (reason: %s).", ErrorString(result).c_str()); return false; } vorbis_info* vorbisInfo = ov_info(&oggStream, -1); // vorbis_comment* vorbisComment = ov_comment(&oggStream, -1); ALenum format; if (vorbisInfo->channels == 1) { format = AL_FORMAT_MONO16; } else if (vorbisInfo->channels == 2) { format = AL_FORMAT_STEREO16; } else { if (strict) { ErrorMessageBox("SoundBuffer::LoadVorbis (%s): invalid number of channels.", file, 0); } else { LOG_L(L_WARNING, "File %s: invalid number of channels: %i", file.c_str(), vorbisInfo->channels); } return false; } size_t pos = 0; std::vector<boost::uint8_t> decodeBuffer(512*1024); // 512kb read buffer int section = 0; long read = 0; do { if (4*pos > 3*decodeBuffer.size()) // enlarge buffer so ov_read has enough space decodeBuffer.resize(decodeBuffer.size()*2); read = ov_read(&oggStream, (char*)&decodeBuffer[pos], decodeBuffer.size() - pos, 0, 2, 1, §ion); switch(read) { case OV_HOLE: LOG_L(L_WARNING, "%s: garbage or corrupt page in stream (non-fatal)", file.c_str()); continue; // read next case OV_EBADLINK: LOG_L(L_WARNING, "%s: corrupted stream", file.c_str()); return false; // abort case OV_EINVAL: LOG_L(L_WARNING, "%s: corrupted headers", file.c_str()); return false; // abort default: break; // all good }; pos += read; } while (read > 0); // read == 0 indicated EOF, read < 0 is error AlGenBuffer(file, format, &decodeBuffer[0], pos, vorbisInfo->rate); filename = file; channels = vorbisInfo->channels; return true; }
int DecodeOgg(FILE* stream, DecodedSound* Sound){ // Passing filestream to libogg int eof=0; OggVorbis_File* vf = (OggVorbis_File*)malloc(sizeof(OggVorbis_File)); static int current_section; fseek(stream, 0, SEEK_SET); if(ov_open(stream, vf, NULL, 0) != 0) { fclose(stream); Output::Warning("Corrupt ogg file"); return -1; } // Grabbing info from the header vorbis_info* my_info = ov_info(vf,-1); Sound->samplerate = my_info->rate; Sound->format = CSND_ENCODING_PCM16; u16 audiotype = my_info->channels; Sound->audiobuf_size = ov_time_total(vf,-1) * (my_info->rate<<1); if (audiotype == 2) Sound->isStereo = true; else Sound->isStereo = false; Sound->bytepersample = audiotype<<1; // Preparing PCM16 audiobuffer #ifdef USE_CACHE allocCache(Sound); #else Sound->audiobuf = (u8*)linearAlloc(Sound->audiobuf_size); #endif if (Player::use_dsp) audiotype = 1; // We trick the decoder since DSP supports native stereo playback // Decoding Vorbis buffer int i = 0; if (audiotype == 1){ // Mono file while(!eof){ long ret=ov_read(vf,(char*)&Sound->audiobuf[i],OGG_BUFSIZE,¤t_section); if (ret == 0) eof=1; else i = i + ret; } }else{ // Stereo file char pcmout[OGG_BUFSIZE]; int z = 0; u32 chn_size = Sound->audiobuf_size>>1; u8* left_channel = Sound->audiobuf; u8* right_channel = &Sound->audiobuf[chn_size]; while(!eof){ long ret=ov_read(vf,pcmout,OGG_BUFSIZE,¤t_section); if (ret == 0) eof=1; else{ for (u32 i=0;i<ret;i=i+4){ memcpy(&left_channel[z],&pcmout[i],2); memcpy(&right_channel[z],&pcmout[i+2],2); z = z + 2; } } } } ov_clear(vf); #ifdef USE_CACHE return LAST_ENTRY; #else return 0; #endif }
int snd_load_file(char const * file, ALuint buffer){ FILE* oggFile; OggVorbis_File oggStream; vorbis_info* vorbisInfo; vorbis_comment* vorbisComment; ALenum format; int result; if(!(oggFile = fopen(file, "rb"))) printf("Could not open Ogg file.\n"); if((result = ov_open(oggFile, &oggStream, NULL, 0)) < 0) { fclose(oggFile); printf("Could not open Ogg stream.\n"); return 0; } vorbisInfo = ov_info(&oggStream, -1); vorbisComment = ov_comment(&oggStream, -1); if(vorbisInfo->channels == 1) format = AL_FORMAT_MONO16; else format = AL_FORMAT_STEREO16; char * dyn_data = NULL; int size = 0; int section; result = 1; printf("Loading sound file %s\n", file); while(result > 0){ char data[BUFFER_SIZE]; result = ov_read(&oggStream, data, BUFFER_SIZE, 0, 2, 1, & section); if(result > 0){ char * tmp; size += result; tmp = (char*)malloc(sizeof(char)*(size)); if(dyn_data != NULL){ memcpy(tmp, dyn_data, sizeof(char)*(size-result)); free(dyn_data); } dyn_data = tmp; tmp += size-result; memcpy(tmp, data, result); } else if(result < 0){ switch(result){ case OV_HOLE: printf("Interruption in the data.%d\n", result); printf("one of: garbage between pages, loss of sync followed by recapture, or a corrupt page\n"); break; case OV_EBADLINK: printf("an invalid stream section was supplied to libvorbisfile, or the requested link is corrupt.\n"); break; case OV_EINVAL: printf("the initial file headers can't be read or are corrupt, or the initial open call for vf failed.\n"); break; } } else if(size == 0){ printf("Date not read.\n"); } } printf("Read %d bytes.\n", size); alBufferData(buffer, format, dyn_data, size, vorbisInfo->rate); free(dyn_data); ov_clear(&oggStream); return 1; }
static void * ogg_player_thread(private_data_ogg * priv) { int first_time = 1; long ret; /* init */ LWP_InitQueue(&oggplayer_queue); priv[0].vi = ov_info(&priv[0].vf, -1); ASND_Pause(0); priv[0].pcm_indx = 0; priv[0].pcmout_pos = 0; priv[0].eof = 0; priv[0].flag = 0; priv[0].current_section = 0; ogg_thread_running = 1; while (!priv[0].eof && ogg_thread_running) { if (priv[0].flag) LWP_ThreadSleep(oggplayer_queue); /* wait only when i have samples to send */ if (priv[0].flag == 0) /* wait to all samples are sended */ { if (ASND_TestPointer(0, priv[0].pcmout[priv[0].pcmout_pos]) && ASND_StatusVoice(0) != SND_UNUSED) { priv[0].flag |= 64; continue; } if (priv[0].pcm_indx < READ_SAMPLES) { priv[0].flag = 3; if (priv[0].seek_time >= 0) { ov_time_seek(&priv[0].vf, priv[0].seek_time); priv[0].seek_time = -1; } ret = ov_read( &priv[0].vf, (void *) &priv[0].pcmout[priv[0].pcmout_pos][priv[0].pcm_indx], MAX_PCMOUT,/*0,2,1,*/&priv[0].current_section); priv[0].flag &= 192; if (ret == 0) { /* EOF */ if (priv[0].mode & 1) ov_time_seek(&priv[0].vf, 0); /* repeat */ else priv[0].eof = 1; /* stops */ } else if (ret < 0) { /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ if (ret != OV_HOLE) { if (priv[0].mode & 1) ov_time_seek(&priv[0].vf, 0); /* repeat */ else priv[0].eof = 1; /* stops */ } } else { /* we don't bother dealing with sample rate changes, etc, but you'll have to */ priv[0].pcm_indx += ret >> 1; /* get 16 bits samples */ } } else priv[0].flag = 1; }
int main(){ OggVorbis_File ov; int i,ret; ogg_int64_t pcmlength; double timelength; char *bigassbuffer; int dummy; #ifdef _WIN32 /* We need to set stdin/stdout to binary mode. Damn windows. */ _setmode( _fileno( stdin ), _O_BINARY ); #endif /* open the file/pipe on stdin */ if(ov_open_callbacks(stdin,&ov,NULL,-1,OV_CALLBACKS_NOCLOSE)<0){ fprintf(stderr,"Could not open input as an OggVorbis file.\n\n"); exit(1); } if(ov_seekable(&ov)){ /* to simplify our own lives, we want to assume the whole file is stereo. Verify this to avoid potentially mystifying users (pissing them off is OK, just don't confuse them) */ for(i=0;i<ov.links;i++){ vorbis_info *vi=ov_info(&ov,i); if(vi->channels!=2){ fprintf(stderr,"Sorry; right now seeking_test can only use Vorbis files\n" "that are entirely stereo.\n\n"); exit(1); } } /* because we want to do sample-level verification that the seek does what it claimed, decode the entire file into memory */ pcmlength=ov_pcm_total(&ov,-1); timelength=ov_time_total(&ov,-1); bigassbuffer=malloc(pcmlength*2); /* w00t */ i=0; while(i<pcmlength*2){ int ret=ov_read(&ov,bigassbuffer+i,pcmlength*2-i,1,1,1,&dummy); if(ret<0)continue; if(ret){ i+=ret; }else{ pcmlength=i/2; } fprintf(stderr,"\rloading.... [%ld left] ", (long)(pcmlength*2-i)); } { ogg_int64_t length=ov.end; fprintf(stderr,"\rtesting raw seeking to random places in %ld bytes....\n", (long)length); for(i=0;i<1000;i++){ ogg_int64_t val=(double)rand()/RAND_MAX*length; fprintf(stderr,"\r\t%d [raw position %ld]... ",i,(long)val); ret=ov_raw_seek(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } _verify(&ov,val,-1,-1.,pcmlength,bigassbuffer); } } fprintf(stderr,"\r"); { fprintf(stderr,"testing pcm page seeking to random places in %ld samples....\n", (long)pcmlength); for(i=0;i<1000;i++){ ogg_int64_t val=(double)rand()/RAND_MAX*pcmlength; fprintf(stderr,"\r\t%d [pcm position %ld]... ",i,(long)val); ret=ov_pcm_seek_page(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } _verify(&ov,-1,val,-1.,pcmlength,bigassbuffer); } } fprintf(stderr,"\r"); { fprintf(stderr,"testing pcm exact seeking to random places in %ld samples....\n", (long)pcmlength); for(i=0;i<1000;i++){ ogg_int64_t val=(double)rand()/RAND_MAX*pcmlength; fprintf(stderr,"\r\t%d [pcm position %ld]... ",i,(long)val); ret=ov_pcm_seek(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } if(ov_pcm_tell(&ov)!=val){ fprintf(stderr,"Declared position didn't perfectly match request: %ld != %ld\n", (long)val,(long)ov_pcm_tell(&ov)); exit(1); } _verify(&ov,-1,val,-1.,pcmlength,bigassbuffer); } } fprintf(stderr,"\r"); { fprintf(stderr,"testing time page seeking to random places in %f seconds....\n", timelength); for(i=0;i<1000;i++){ double val=(double)rand()/RAND_MAX*timelength; fprintf(stderr,"\r\t%d [time position %f]... ",i,val); ret=ov_time_seek_page(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } _verify(&ov,-1,-1,val,pcmlength,bigassbuffer); } } fprintf(stderr,"\r"); { fprintf(stderr,"testing time exact seeking to random places in %f seconds....\n", timelength); for(i=0;i<1000;i++){ double val=(double)rand()/RAND_MAX*timelength; fprintf(stderr,"\r\t%d [time position %f]... ",i,val); ret=ov_time_seek(&ov,val); if(ret<0){ fprintf(stderr,"seek failed: %d\n",ret); exit(1); } if(ov_time_tell(&ov)<val-1 || ov_time_tell(&ov)>val+1){ fprintf(stderr,"Declared position didn't perfectly match request: %f != %f\n", val,ov_time_tell(&ov)); exit(1); } _verify(&ov,-1,-1,val,pcmlength,bigassbuffer); } } fprintf(stderr,"\r \nOK.\n\n"); }else{ fprintf(stderr,"Standard input was not seekable.\n"); } ov_clear(&ov); return 0; }
bool OGG::Decode (Resource *resource, AudioBuffer *audioBuffer) { OggVorbis_File oggFile; if (resource->path) { FILE_HANDLE *file = lime::fopen (resource->path, "rb"); if (!file) { return false; } if (file->isFile ()) { ov_open (file->getFile (), &oggFile, NULL, file->getLength ()); } else { ByteArray data = ByteArray (resource->path); OAL_OggMemoryFile fakeFile = { data.Bytes (), data.Size (), 0 }; if (ov_open_callbacks (&fakeFile, &oggFile, NULL, 0, OAL_CALLBACKS_BUFFER) != 0) { return false; } } } else { OAL_OggMemoryFile fakeFile = { resource->data->Bytes (), resource->data->Size (), 0 }; if (ov_open_callbacks (&fakeFile, &oggFile, NULL, 0, OAL_CALLBACKS_BUFFER) != 0) { return false; } } // 0 for Little-Endian, 1 for Big-Endian #ifdef HXCPP_BIG_ENDIAN #define BUFFER_READ_TYPE 1 #else #define BUFFER_READ_TYPE 0 #endif int bitStream; long bytes = 1; int totalBytes = 0; #define BUFFER_SIZE 32768 vorbis_info *pInfo = ov_info (&oggFile, -1); if (pInfo == NULL) { //LOG_SOUND("FAILED TO READ OGG SOUND INFO, IS THIS EVEN AN OGG FILE?\n"); return false; } audioBuffer->channels = pInfo->channels; audioBuffer->sampleRate = pInfo->rate; //default to 16? todo audioBuffer->bitsPerSample = 16; // Seem to need four times the read PCM total audioBuffer->data->Resize (ov_pcm_total (&oggFile, -1) * 4); while (bytes > 0) { if (audioBuffer->data->Size () < totalBytes + BUFFER_SIZE) { audioBuffer->data->Resize (totalBytes + BUFFER_SIZE); } bytes = ov_read (&oggFile, (char *)audioBuffer->data->Bytes () + totalBytes, BUFFER_SIZE, BUFFER_READ_TYPE, 2, 1, &bitStream); totalBytes += bytes; } audioBuffer->data->Resize (totalBytes); ov_clear (&oggFile); #undef BUFFER_SIZE #undef BUFFER_READ_TYPE return true; }
static void ogg_play_task(mp_callback_func cb) { long ret = 0; int current_section = 0; double time_seek_to = 0; vorbis_info *vi; struct snd_device *sound_dev; int *processed_pcm; double song_time; PE_DBG_PRINTF("MusicEngine: ==> ogg_play_task()! \n"); sound_dev = (struct snd_device*)dev_get_by_type(NULL, HLD_DEV_TYPE_SND); processed_pcm = (int*)ogg_file->processed_pcm_buff; if (ov_open(ogg_file->file, &ogg_file->vf, NULL, 0) < 0) { PE_DBG_PRINTF("MusicEngine: ogg_play_task() ov_open failed! \n"); #ifdef ENABLE_PE_CACHE pe_cache_close(ogg_cache_id); // 这个ogg_cache_id是在play_file时打开 ogg_cache_id = -1; #else fclose(ogg_file->file); #endif //FREE(processed_pcm); osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_UNSUCCESSFUL); return; } else { PE_DBG_PRINTF("MusicEngine: ov_opened \n"); { vorbis_info *vi = ov_info(&ogg_file->vf, -1); if (!vi) { PE_DBG_PRINTF("MusicEngine: ov_info failed!\n"); ov_clear(&ogg_file->vf); osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_UNSUCCESSFUL); return; } ogg_file->samplerate = vi->rate; ogg_file->channel = vi->channels; PE_DBG_PRINTF("\nBitstream is %d channel, %ldHz\n", vi->channels, vi->rate); song_time = ov_time_total(&ogg_file->vf, -1); if (song_time <= 0) { PE_DBG_PRINTF("MusicEngine: ov_info failed!\n"); ov_clear(&ogg_file->vf); osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_UNSUCCESSFUL); } } osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_SUCCESS); } //all work success, we can start to play while (ogg_file->command != OGG_CMD_STOP) { if (ogg_file->seek_to != 0) { time_seek_to = ov_time_tell(&ogg_file->vf); time_seek_to = time_seek_to + (ogg_file->seek_to * 1000); if (time_seek_to < 0) { time_seek_to = 0; } else if (time_seek_to > song_time) { time_seek_to = song_time; } ret = ov_time_seek(&ogg_file->vf, time_seek_to); if (ret < 0) { //seek failed } osal_task_dispatch_off(); ogg_file->seek_to = 0; osal_task_dispatch_on(); } if (ogg_file->command == OGG_CMD_NONE) { ret = ov_read(&ogg_file->vf, (void *)ogg_file->pcm_out_buff, 2304, ¤t_section); if (ret == 0) { PE_DBG_PRINTF("file end!\n"); //EOF we need call back osal_task_dispatch_off(); if (ogg_file->command != OGG_CMD_STOP) { ogg_file->command = OGG_CMD_WAIT_FOR_STOP; } osal_task_dispatch_on(); cb(MP_MUSIC_PLAYBACK_END, 0); osal_task_sleep(10); } else if (ret < 0) { PE_DBG_PRINTF("error!!!\n"); /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ osal_task_dispatch_off(); if (ogg_file->command != OGG_CMD_STOP) { ogg_file->command = OGG_CMD_WAIT_FOR_STOP; } osal_task_dispatch_on(); cb(MP_MUSIC_PLAYBACK_END, 0); osal_task_sleep(10); } else { /* we don't bother dealing with sample rate changes, etc, but you'll have to*/ process_ogg_pcm(sound_dev, ret, processed_pcm); } } else { osal_task_sleep(10); } } ov_clear(&ogg_file->vf); ogg_avoid_under_run = 0; snd_io_control(sound_dev, SND_CC_MUTE, 0); snd_stop(sound_dev); //FREE(processed_pcm); osal_flag_set(ogg_engine.ogg_engine_flag_id, OGG_ENGINE_FLAG_TASK_EXIT); // task结束,发出EXIT消息 PE_DBG_PRINTF("MusicEngine: <== ogg_play_task()! \n"); }
bool OGG::Decode (Resource *resource, AudioBuffer *audioBuffer) { OggVorbis_File oggFile; if (resource->path) { FILE_HANDLE *file = lime::fopen (resource->path, "rb"); if (!file) { return false; } if (file->isFile ()) { if (ov_open (file->getFile (), &oggFile, NULL, file->getLength ()) != 0) { lime::fclose (file); return false; } } else { lime::fclose (file); Bytes data = Bytes (resource->path); OAL_OggMemoryFile fakeFile = { data.Data (), data.Length (), 0 }; if (ov_open_callbacks (&fakeFile, &oggFile, NULL, 0, OAL_CALLBACKS_BUFFER) != 0) { return false; } } } else { OAL_OggMemoryFile fakeFile = { resource->data->Data (), resource->data->Length (), 0 }; if (ov_open_callbacks (&fakeFile, &oggFile, NULL, 0, OAL_CALLBACKS_BUFFER) != 0) { return false; } } // 0 for Little-Endian, 1 for Big-Endian #ifdef HXCPP_BIG_ENDIAN #define BUFFER_READ_TYPE 1 #else #define BUFFER_READ_TYPE 0 #endif int bitStream; long bytes = 1; int totalBytes = 0; #define BUFFER_SIZE 4096 vorbis_info *pInfo = ov_info (&oggFile, -1); if (pInfo == NULL) { //LOG_SOUND("FAILED TO READ OGG SOUND INFO, IS THIS EVEN AN OGG FILE?\n"); ov_clear (&oggFile); return false; } audioBuffer->channels = pInfo->channels; audioBuffer->sampleRate = pInfo->rate; audioBuffer->bitsPerSample = 16; int dataLength = ov_pcm_total (&oggFile, -1) * audioBuffer->channels * audioBuffer->bitsPerSample / 8; audioBuffer->data->Resize (dataLength); while (bytes > 0) { bytes = ov_read (&oggFile, (char *)audioBuffer->data->Data () + totalBytes, BUFFER_SIZE, BUFFER_READ_TYPE, 2, 1, &bitStream); totalBytes += bytes; } if (dataLength != totalBytes) { audioBuffer->data->Resize (totalBytes); } ov_clear (&oggFile); #undef BUFFER_READ_TYPE return true; }
Sound* AudioStreamer::LoadSound(IXAudio2* xaudio2, const std::string& file) { if( !xaudio2 ) { SND_ERROR("AudioStreamer::LoadSound(): NULL == xaudio2"); return false; } FILE* infile = NULL; fopen_s(&infile, file.c_str(), "rb"); if( !infile ) { SND_ERROR("AudioStreamer::LoadSound(): Could not open file"); return NULL; } OggVorbis_File oggfile; int stream; long readbytes = 0; long totalread = 0; ov_open(infile, &oggfile, NULL, 0); vorbis_info* info = ov_info(&oggfile, -1); Sound* s = new Sound(); s->format.nChannels = info->channels; s->format.cbSize = sizeof(WAVEFORMATEX); s->format.wBitsPerSample = 16; s->format.nSamplesPerSec = info->rate; s->format.nAvgBytesPerSec = info->rate * 2 * info->channels; s->format.nBlockAlign = 2 * info->channels; s->format.wFormatTag = 1; s->totalsize = (unsigned int)ov_pcm_total(&oggfile, -1) * 2 * info->channels; s->data[0] = new char[s->totalsize]; do { readbytes = ov_read(&oggfile, s->data[0] + totalread, s->totalsize - totalread, 0, 2, 1, &stream); totalread += readbytes; } while( readbytes > 0 && (unsigned int)totalread < s->totalsize ); ov_clear(&oggfile); // create xaudio voice object if( FAILED(xaudio2->CreateSourceVoice(&s->voice, &s->format, 0, 2.0f, s)) ) { SND_ERROR("AudioStreamer::LoadSound(): Could not create source voice"); delete s; return NULL; } XAUDIO2_BUFFER audbuff; memset(&audbuff, 0, sizeof(XAUDIO2_BUFFER)); audbuff.pAudioData = (const BYTE*)s->data[0]; audbuff.Flags = XAUDIO2_END_OF_STREAM; audbuff.AudioBytes = s->totalsize; audbuff.LoopCount = XAUDIO2_LOOP_INFINITE; if( FAILED(s->voice->SubmitSourceBuffer(&audbuff)) ) { SND_ERROR("AudioStreamer::LoadSound(): Could not submit buffer"); delete s; return NULL; } s->canplay = true; // called from main thread soundguard.Lock(); sound.push_back(s); soundguard.Unlock(); return s; }
void AudioStreamer::Update() { // this method must run on separate thread!!! XAUDIO2_VOICE_STATE state; Sound* s; soundlist canstream; int stream; long readbytes; long totalread; long toread; bool play; // must be called in every thread CoInitializeEx(0, COINIT_MULTITHREADED); while( running ) { // collect sound that need more data canstream.clear(); soundguard.Lock(); // reading 'sound' for( soundlist::iterator it = sound.begin(); it != sound.end(); ++it ) { s = (*it); if( s->isstream ) { if( (s->readsize < s->totalsize) && (s->freebuffers > 0) ) canstream.push_back(s); } } soundguard.Unlock(); // update collected sound if( canstream.size() > 0 ) { for( soundlist::iterator it = canstream.begin(); it != canstream.end(); ++it ) { soundguard.Lock(); // watch out for 'Destroy()' // might have exited if( !running ) return; s = (*it); totalread = 0; readbytes = 0; toread = min(STREAMING_BUFFER_SIZE, s->totalsize - s->readsize); // fill a free buffer with data do { readbytes = ov_read(&s->oggfile, s->data[s->currentbuffer] + totalread, toread - totalread, 0, 2, 1, &stream); totalread += readbytes; } while( readbytes > 0 && totalread < toread ); s->readsize += totalread; SND_DEBUG("buffer " << s->currentbuffer << " loaded"); // pull buffer to queue if possible // otherwise the sound is gonna pull it s->voice->GetState(&state); if( state.BuffersQueued < MAX_BUFFER_COUNT - 1 ) { s->PullBuffer(s->currentbuffer); SND_DEBUG("buffer " << s->currentbuffer << " pulled (instantly)"); // lock it so noone can modify s->playing s->playguard.Lock(); { s->canplay = true; play = (s->playrequest && !s->playing); } s->playguard.Unlock(); if( play ) s->Play(); } s->currentbuffer = (s->currentbuffer + 1) % MAX_BUFFER_COUNT; --s->freebuffers; soundguard.Unlock(); } } else Sleep(100); } CoUninitialize(); }
soundDataBuffer* sound_DecodeOggVorbis(struct OggVorbisDecoderState* decoder, size_t bufferSize) { size_t size = 0; #ifndef WZ_NOSOUND int result; #endif soundDataBuffer* buffer; ASSERT(decoder != NULL, "NULL decoder passed!"); #ifndef WZ_NOSOUND if (decoder->allowSeeking) { unsigned int sampleCount = getSampleCount(decoder); unsigned int sizeEstimate = sampleCount * decoder->VorbisInfo->channels * 2; if (((bufferSize == 0) || (bufferSize > sizeEstimate)) && (sizeEstimate != 0)) { bufferSize = (sampleCount - getCurrentSample(decoder)) * decoder->VorbisInfo->channels * 2; } } // If we can't seek nor receive any suggested size for our buffer, just quit if (bufferSize == 0) { debug(LOG_ERROR, "can't find a proper buffer size"); return NULL; } #else bufferSize = 0; #endif buffer = malloc(bufferSize + sizeof(soundDataBuffer)); if (buffer == NULL) { debug(LOG_ERROR, "couldn't allocate memory (%lu bytes requested)", (unsigned long) bufferSize + sizeof(soundDataBuffer)); return NULL; } buffer->data = (char*)(buffer + 1); buffer->bufferSize = bufferSize; buffer->bitsPerSample = 16; #ifndef WZ_NOSOUND buffer->channelCount = decoder->VorbisInfo->channels; buffer->frequency = decoder->VorbisInfo->rate; // Decode PCM data into the buffer until there is nothing to decode left do { // Decode int section; result = ov_read(&decoder->oggVorbis_stream, &buffer->data[size], bufferSize - size, OGG_ENDIAN, 2, 1, §ion); if (result < 0) { debug(LOG_ERROR, "error decoding from OggVorbis file; errorcode from ov_read: %s", wz_oggVorbis_getErrorStr(result)); free(buffer); return NULL; } else { size += result; } } while ((result != 0 && size < bufferSize)); #endif buffer->size = size; return buffer; }
int OggImportFileHandle::Import(TrackFactory *trackFactory, Track ***outTracks, int *outNumTracks, Tags *tags) { wxASSERT(mFile->IsOpened()); CreateProgress(); //Number of streams used may be less than mVorbisFile->links, //but this way bitstream matches array index. mChannels = new WaveTrack **[mVorbisFile->links]; int i,c; for (i = 0; i < mVorbisFile->links; i++) { //Stream is not used if (mStreamUsage[i] == 0) { //This is just a padding to keep bitstream number and //array indices matched. mChannels[i] = NULL; continue; } vorbis_info *vi = ov_info(mVorbisFile, i); mChannels[i] = new WaveTrack *[vi->channels]; for (c = 0; c < vi->channels; c++) { mChannels[i][c] = trackFactory->NewWaveTrack(int16Sample, vi->rate); if (vi->channels == 2) { switch (c) { case 0: mChannels[i][c]->SetChannel(Track::LeftChannel); mChannels[i][c]->SetLinked(true); break; case 1: mChannels[i][c]->SetChannel(Track::RightChannel); break; } } else { mChannels[i][c]->SetChannel(Track::MonoChannel); } } } /* The number of bytes to get from the codec in each run */ #define CODEC_TRANSFER_SIZE 4096 /* The number of samples to read between calls to the callback. * Balance between responsiveness of the GUI and throughput of import. */ #define SAMPLES_PER_CALLBACK 100000 short *mainBuffer = new short[CODEC_TRANSFER_SIZE]; /* determine endianness (clever trick courtesy of Nicholas Devillard, * (http://www.eso.org/~ndevilla/endian/) */ int testvar = 1, endian; if(*(char *)&testvar) endian = 0; // little endian else endian = 1; // big endian /* number of samples currently in each channel's buffer */ int updateResult = eProgressSuccess; long bytesRead = 0; long samplesRead = 0; int bitstream = 0; int samplesSinceLastCallback = 0; // You would think that the stream would already be seeked to 0, and // indeed it is if the file is legit. But I had several ogg files on // my hard drive that have malformed headers, and this added call // causes them to be read correctly. Otherwise they have lots of // zeros inserted at the beginning ov_pcm_seek(mVorbisFile, 0); do { /* get data from the decoder */ bytesRead = ov_read(mVorbisFile, (char *) mainBuffer, CODEC_TRANSFER_SIZE, endian, 2, // word length (2 for 16 bit samples) 1, // signed &bitstream); if (bytesRead == OV_HOLE) { wxFileName f(mFilename); wxLogError(wxT("Ogg Vorbis importer: file %s is malformed, ov_read() reported a hole"), f.GetFullName().c_str()); /* http://lists.xiph.org/pipermail/vorbis-dev/2001-February/003223.html * is the justification for doing this - best effort for malformed file, * hence the message. */ continue; } else if (bytesRead < 0) { /* Malformed Ogg Vorbis file. */ /* TODO: Return some sort of meaningful error. */ wxLogError(wxT("Ogg Vorbis importer: ov_read() returned error %i"), bytesRead); break; } samplesRead = bytesRead / mVorbisFile->vi[bitstream].channels / sizeof(short); /* give the data to the wavetracks */ if (mStreamUsage[bitstream] != 0) { for (c = 0; c < mVorbisFile->vi[bitstream].channels; c++) mChannels[bitstream][c]->Append((char *)(mainBuffer + c), int16Sample, samplesRead, mVorbisFile->vi[bitstream].channels); } samplesSinceLastCallback += samplesRead; if (samplesSinceLastCallback > SAMPLES_PER_CALLBACK) { updateResult = mProgress->Update(ov_time_tell(mVorbisFile), ov_time_total(mVorbisFile, bitstream)); samplesSinceLastCallback -= SAMPLES_PER_CALLBACK; } } while (updateResult == eProgressSuccess && bytesRead != 0); delete[]mainBuffer; int res = updateResult; if (bytesRead < 0) res = eProgressFailed; if (res == eProgressFailed || res == eProgressCancelled) { for (i = 0; i < mVorbisFile->links; i++) { if (mChannels[i]) { for(c = 0; c < mVorbisFile->vi[bitstream].channels; c++) { if (mChannels[i][c]) delete mChannels[i][c]; } delete[] mChannels[i]; } } delete[] mChannels; return res; } *outNumTracks = 0; for (int s = 0; s < mVorbisFile->links; s++) { if (mStreamUsage[s] != 0) *outNumTracks += mVorbisFile->vi[s].channels; } *outTracks = new Track *[*outNumTracks]; int trackindex = 0; for (i = 0; i < mVorbisFile->links; i++) { if (mChannels[i]) { for (c = 0; c < mVorbisFile->vi[i].channels; c++) { mChannels[i][c]->Flush(); (*outTracks)[trackindex++] = mChannels[i][c]; } delete[] mChannels[i]; } } delete[] mChannels; //\todo { Extract comments from each stream? } if (mVorbisFile->vc[0].comments > 0) { tags->Clear(); for (c = 0; c < mVorbisFile->vc[0].comments; c++) { wxString comment = UTF8CTOWX(mVorbisFile->vc[0].user_comments[c]); wxString name = comment.BeforeFirst(wxT('=')); wxString value = comment.AfterFirst(wxT('=')); if (name.Upper() == wxT("DATE") && !tags->HasTag(TAG_YEAR)) { long val; if (value.Length() == 4 && value.ToLong(&val)) { name = TAG_YEAR; } } tags->SetTag(name, value); } } return res; }
static int s_ogg_decoder( SAL_Device *p_device, sal_voice_t voice, sal_byte_t *p_dst, int bytes_needed ) { int bytes_read = 0; SAL_Sample *sample = 0; SALx_OggArgs *ogg_args = 0; int big_endian = 0; int cursor = 0; #if POSH_BIG_ENDIAN big_endian = 1; #endif SAL_get_voice_sample( p_device, voice, &sample ); SAL_get_voice_cursor( p_device, voice, &cursor ); ogg_args = ( SALx_OggArgs * ) sample->sample_args.sarg_ptr; /* first seek to the voice's sample */ ov_pcm_seek( &ogg_args->oa_file, cursor ); /* then read stuff out */ while ( bytes_read < bytes_needed ) { long lret; lret = ov_read( &ogg_args->oa_file, /* vorbis file */ p_dst + bytes_read, /* destination buffer */ bytes_needed - bytes_read, /* size of the destination buffer*/ big_endian, /* endianess, 0 == little, 1 == big */ 2, /* bytes per sample */ 1, /* 0 == unsigned, 1 == signed */ &ogg_args->oa_section ); /* pointer to number of current logical bitstream */ if ( lret == 0 ) { /* rewind the stream */ ov_pcm_seek( &ogg_args->oa_file, 0 ); } else if ( lret < 0 ) { /* error */ break; } else { bytes_read += lret; /** @todo update to handle different size samples */ if ( !_SAL_advance_voice( p_device, voice, lret / ( ogg_args->oa_num_channels * 2 ) ) ) { return 1; } } } return 0; }
int alogg_poll_ogg(ALOGG_OGG *ogg) { void *audiobuf; char *audiobuf_p; int i, size_done; unsigned short* data_array; int x; /* continue only if we are playing it */ if (!alogg_is_playing_ogg(ogg)) return ALOGG_POLL_NOTPLAYING; /* get the audio stream buffer and only continue if we need to fill it */ audiobuf = get_audio_stream_buffer(ogg->audiostream); if (audiobuf == NULL) return ALOGG_OK; /* clear the buffer with 16bit unsigned data */ { int i; unsigned short *j = (unsigned short *)audiobuf; for (i = 0; i < (ogg->audiostream_buffer_len / 2); i++, j++) *j = 0x8000; } /* if we need to fill it, but we were just waiting for it to finish */ if (!ogg->loop) { if (ogg->wait_for_audio_stop > 0) { free_audio_stream_buffer(ogg->audiostream); if (--ogg->wait_for_audio_stop == 0) { /* stop it */ //rest(500); alogg_stop_ogg(ogg); return ALOGG_POLL_PLAYJUSTFINISHED; } else return ALOGG_OK; } } audiobuf_p = (char *)audiobuf; size_done = 0; for (i = ogg->audiostream_buffer_len; i > 0; i -= size_done) { /* decode */ size_done = ov_read(&(ogg->vf), audiobuf_p, i, WANT_BIG_ENDIAN, 2, 0, &(ogg->current_section)); #ifdef USE_TREMOR /* Add offset to data because we are using libtremor */ data_array = (unsigned short*)audiobuf_p; for (x = 0; x < size_done / 2; x++) { data_array[x] += 0x8000; } #endif /* check if the decoding was not successful */ if (size_done < 0) { if (size_done == OV_HOLE) size_done = 0; else { free_audio_stream_buffer(ogg->audiostream); alogg_stop_ogg(ogg); alogg_rewind_ogg(ogg); return ALOGG_POLL_FRAMECORRUPT; } } else if (size_done == 0) { /* we have reached the end */ alogg_rewind_ogg(ogg); if (!ogg->loop) { free_audio_stream_buffer(ogg->audiostream); ogg->wait_for_audio_stop = 2; return ALOGG_OK; } } audiobuf_p += size_done; } /* lock the buffer */ free_audio_stream_buffer(ogg->audiostream); return ALOGG_OK; }
int OpenOgg(FILE* stream, DecodedMusic* Sound){ // Setting return code (to check if audio streaming is needed or not) u8 res = 0; // Passing filestream to libogg int eof=0; OggVorbis_File* vf = (OggVorbis_File*)malloc(sizeof(OggVorbis_File)); static int current_section; fseek(stream, 0, SEEK_SET); if(ov_open(stream, vf, NULL, 0) != 0) { fclose(stream); Output::Warning("Corrupt ogg file"); return -1; } // Grabbing info from the header vorbis_info* my_info = ov_info(vf,-1); Sound->samplerate = my_info->rate; Sound->format = CSND_ENCODING_PCM16; u16 audiotype = my_info->channels; Sound->audiobuf_size = ov_time_total(vf,-1) * (my_info->rate<<1); if (audiotype == 2) Sound->isStereo = true; else Sound->isStereo = false; Sound->bytepersample = audiotype<<1; // Preparing PCM16 audiobuffer if (Sound->audiobuf_size <= BGM_BUFSIZE) res = 1; else{ while (Sound->audiobuf_size > BGM_BUFSIZE){ Sound->audiobuf_size = Sound->audiobuf_size>>1; } } Sound->audiobuf = (u8*)linearAlloc(Sound->audiobuf_size); if (Player::use_dsp) audiotype = 1; // We trick the decoder since DSP supports native stereo playback // Decoding Vorbis buffer int i = 0; if (audiotype == 1){ // Mono file while(!eof){ long ret=ov_read(vf,(char*)&Sound->audiobuf[i],OGG_BUFSIZE,¤t_section); if (ret == 0) eof=1; else i = i + ret; } }else{ // Stereo file char pcmout[OGG_BUFSIZE]; int z = 0; u32 chn_size = Sound->audiobuf_size>>1; u8* left_channel = Sound->audiobuf; u8* right_channel = &Sound->audiobuf[chn_size]; while(!eof){ long ret=ov_read(vf,pcmout,OGG_BUFSIZE,¤t_section); if (ret == 0) eof=1; else{ for (u32 i=0;i<ret;i=i+4){ memcpy(&left_channel[z],&pcmout[i],2); memcpy(&right_channel[z],&pcmout[i+2],2); z = z + 2; } } } } //Setting default streaming values Sound->block_idx = 1; if (res == 0) Sound->handle = (FILE*)vf; // We pass libogg filestream instead of stdio ones else{ ov_clear(vf); Sound->handle = NULL; } Sound->eof_idx = 0xFFFFFFFF; Sound->updateCallback = UpdateOggStream; Sound->closeCallback = CloseOgg; return res; }
SAMPLE *alogg_create_sample_from_ogg(ALOGG_OGG *ogg) { SAMPLE *sample; char *data; int i, sample_len_bytes, sample_len, size_done, done; unsigned short* data_array; int x; /* first we need to calculate the len of the sample in bytes */ sample_len = ov_pcm_total(&(ogg->vf), -1); sample_len_bytes = (sample_len * (ogg->stereo ? 2 : 1)) * 2; /* / 2 = 16 bits */ /* create the sample */ sample = create_sample(16, ogg->stereo, ogg->freq, sample_len); /* return NULL if we were not able to allocate the memory for it */ if (sample == NULL) return NULL; /* we need to stop and rewind the ogg */ alogg_stop_ogg(ogg); alogg_rewind_ogg(ogg); /* set our pointer */ data = (char *)sample->data; /* clear the sample buffer in unsigned format */ { int i; unsigned short *j = (unsigned short *)data; for (i = 0; i < (sample_len_bytes / 2); i++, j++) *j = 0x8000; } /* decode */ done = FALSE; size_done = 0; for (i = sample_len_bytes; !done && (i > 0); i -= size_done) { /* decode */ size_done = ov_read(&(ogg->vf), data, i, WANT_BIG_ENDIAN, 2, 0, &(ogg->current_section)); #ifdef USE_TREMOR /* Add offset to data because we are using libtremor. */ data_array = (unsigned short*)data; for (x = 0; x < size_done / 2; x++) { data_array[x] += 0x8000; } #endif /* check if the decoding was not successful */ if (size_done < 0) { if (size_done == OV_HOLE) size_done = 0; else { alogg_rewind_ogg(ogg); destroy_sample(sample); return NULL; } } else if (size_done == 0) done = TRUE; data += size_done; } alogg_rewind_ogg(ogg); return sample; }
/** * @brief Loads the specified sound file and decodes its content into an OpenAL buffer. * @param file_name name of the file to open * @return the buffer created, or AL_NONE if the sound could not be loaded */ ALuint Sound::decode_file(const std::string &file_name) { ALuint buffer = AL_NONE; // load the sound file SoundFromMemory mem; mem.position = 0; FileTools::data_file_open_buffer(file_name, &mem.data, &mem.size); OggVorbis_File file; int error = ov_open_callbacks(&mem, &file, NULL, 0, ogg_callbacks); if (error) { std::cout << "Cannot load sound file from memory: error " << error << std::endl; } else { // read the encoded sound properties vorbis_info* info = ov_info(&file, -1); ALsizei sample_rate = info->rate; ALenum format = AL_NONE; if (info->channels == 1) { format = AL_FORMAT_MONO16; } else if (info->channels == 2) { format = AL_FORMAT_STEREO16; } if (format == AL_NONE) { std::cout << "Invalid audio format" << std::endl; } else { // decode the sound with vorbisfile std::vector<char> samples; int bitstream; long bytes_read; long total_bytes_read = 0; char samples_buffer[4096]; do { bytes_read = ov_read(&file, samples_buffer, 4096, 0, 2, 1, &bitstream); if (bytes_read < 0) { std::cout << "Error while decoding ogg chunk: " << bytes_read << std::endl; } else { total_bytes_read += bytes_read; if (format == AL_FORMAT_STEREO16) { samples.insert(samples.end(), samples_buffer, samples_buffer + bytes_read); } else { // mono sound files make no sound on some machines // workaround: convert them on-the-fly into stereo sounds // TODO find a better solution for (int i = 0; i < bytes_read; i += 2) { samples.insert(samples.end(), samples_buffer + i, samples_buffer + i + 2); samples.insert(samples.end(), samples_buffer + i, samples_buffer + i + 2); } total_bytes_read += bytes_read; } } } while (bytes_read > 0); // copy the samples into an OpenAL buffer alGenBuffers(1, &buffer); alBufferData(buffer, AL_FORMAT_STEREO16, (ALshort*) &samples[0], total_bytes_read, sample_rate); if (alGetError() != AL_NO_ERROR) { std::cout << "Cannot copy the sound samples into buffer " << buffer << "\n"; buffer = AL_NONE; } } ov_clear(&file); } FileTools::data_file_close_buffer(mem.data); return buffer; }
int alogg_poll_oggstream(ALOGG_OGGSTREAM *ogg) { void *audiobuf; char *audiobuf_p; int i, size_done; int last_block; unsigned short* data_array; int x; /* continue only if we are playing it */ if (!alogg_is_playing_oggstream(ogg)) return ALOGG_POLL_NOTPLAYING; /* get the audio stream buffer and only continue if we need to fill it */ audiobuf = get_audio_stream_buffer(ogg->audiostream); if (audiobuf == NULL) return ALOGG_OK; /* clear the buffer with unsinged data*/ { int i; unsigned short *j = (unsigned short *)audiobuf; for (i = 0; i < (ogg->audiostream_buffer_len / 2); i++, j++) *j = 0x8000; } /* if we need to fill it, but we were just waiting for it to finish */ if (ogg->wait_for_audio_stop > 0) { free_audio_stream_buffer(ogg->audiostream); if (--ogg->wait_for_audio_stop == 0) { /* stop it */ alogg_stop_oggstream(ogg); return ALOGG_POLL_PLAYJUSTFINISHED; } else return ALOGG_OK; } /* get if this will be the last block to be processed */ if (ogg->bytes_used != -1) last_block = TRUE; else last_block = FALSE; audiobuf_p = (char *)audiobuf; size_done = 0; for (i = ogg->audiostream_buffer_len; i > 0; i -= size_done) { size_done = ov_read(&(ogg->vf), audiobuf_p, i, WANT_BIG_ENDIAN, 2, 0, &(ogg->current_section)); #ifdef USE_TREMOR /* Add offset to data because we are using libtremor. */ data_array = (unsigned short*)audiobuf_p; for (x = 0; x < size_done / 2; x++) { data_array[x] += 0x8000; } #endif /* check if the decoding was not successful */ if (size_done < 0) { if (size_done == OV_HOLE) size_done = 0; else { free_audio_stream_buffer(ogg->audiostream); alogg_stop_oggstream(ogg); return ALOGG_POLL_FRAMECORRUPT; } } else if (size_done == 0) { free_audio_stream_buffer(ogg->audiostream); /* if this was not the last block, buffer underrun */ if (!last_block) { alogg_stop_oggstream(ogg); return ALOGG_POLL_BUFFERUNDERRUN; } /* else we just finished playing, we need to wait for audio to stop */ else { ogg->wait_for_audio_stop = 2; return ALOGG_OK; } } audiobuf_p += size_done; } /* lock the buffer */ free_audio_stream_buffer(ogg->audiostream); return ALOGG_OK; }
static ALuint createBufferFromOGG(const char *pszFilePath) { ALuint buffer; OggVorbis_File ogg_file; vorbis_info* info; ALenum format; int result; int section; int err; unsigned int size = 0; if (ov_fopen(pszFilePath, &ogg_file) < 0) { ov_clear(&ogg_file); fprintf(stderr, "Could not open OGG file %s\n", pszFilePath); return -1; } info = ov_info(&ogg_file, -1); if (info->channels == 1) format = AL_FORMAT_MONO16; else format = AL_FORMAT_STEREO16; // size = #samples * #channels * 2 (for 16 bit) unsigned int data_size = ov_pcm_total(&ogg_file, -1) * info->channels * 2; char* data = new char[data_size]; while (size < data_size) { result = ov_read(&ogg_file, data + size, data_size - size, 0, 2, 1, §ion); if (result > 0) { size += result; } else if (result < 0) { delete [] data; fprintf(stderr, "OGG file problem %s\n", pszFilePath); return -1; } else { break; } } if (size == 0) { delete [] data; fprintf(stderr, "Unable to read OGG data\n"); return -1; } // clear al errors checkALError("createBufferFromOGG"); // Load audio data into a buffer. alGenBuffers(1, &buffer); if (checkALError("createBufferFromOGG") != AL_NO_ERROR) { fprintf(stderr, "Couldn't generate a buffer for OGG file\n"); delete [] data; return buffer; } alBufferData(buffer, format, data, data_size, info->rate); checkALError("createBufferFromOGG"); delete [] data; ov_clear(&ogg_file); return buffer; }
static void * ogg_player_thread(private_data_ogg * priv) { int first_time = 1; long ret; int offs; u_int *buff; //init LWP_InitQueue(&oggplayer_queue); priv[0].vi = ov_info(&priv[0].vf, -1); ASND_Pause(0); priv[0].pcm_indx = 0; priv[0].pcmout_pos = 0; priv[0].eof = 0; priv[0].flag = 0; priv[0].current_section = 0; ogg_thread_running = 1; while (!priv[0].eof && ogg_thread_running) { if (priv[0].flag) LWP_ThreadSleep(oggplayer_queue); // wait only when i have samples to send if (priv[0].flag == 0) // wait to all samples are sent { if (ASND_TestPointer(0, priv[0].pcmout[priv[0].pcmout_pos]) && ASND_StatusVoice(0) != SND_UNUSED) { priv[0].flag |= 64; continue; } if (priv[0].pcm_indx < READ_SAMPLES) { priv[0].flag = 3; if (priv[0].seek_time >= 0) { ov_time_seek(&priv[0].vf, priv[0].seek_time); priv[0].seek_time = -1; } ret = ov_read( &priv[0].vf, (void*)&priv[0].pcmout[priv[0].pcmout_pos][priv[0].pcm_indx], MAX_PCMOUT,/*0,2,1,*/&priv[0].current_section); priv[0].flag &= 192; if (ret == 0) { /* EOF */ if (priv[0].mode & 1) ov_pcm_seek(&priv[0].vf, ogg_loop_start); // repeat else priv[0].eof = 1; // stops } else if (ret < 0) { /* error in the stream. Not a problem, just reporting it in case we (the app) cares. In this case, we don't. */ if (ret != OV_HOLE) { if (priv[0].mode & 1) ov_time_seek(&priv[0].vf, 0); // repeat else priv[0].eof = 1; // stops } } else { /* we don't bother dealing with sample rate changes, etc, but you'll have to*/ // Reverse stereo fix added by Lameguy64/TheCodingBrony if (priv[0].vi->channels == 2) { buff=(u_int*)&priv[0].pcmout[priv[0].pcmout_pos][priv[0].pcm_indx]; for(offs=0; offs<ret/4; offs+=1) { buff[offs] = SWAPINT(buff[offs]); } } priv[0].pcm_indx += ret >> 1; //get 16 bits samples } } else priv[0].flag = 1; }
int slimaudio_decoder_vorbis_process(slimaudio_t *audio) { int err; assert(audio != NULL); DEBUGF("slimaudio_decoder_vorbis_process: start\n"); ov_callbacks callbacks; callbacks.read_func = vorbis_read_func; callbacks.seek_func = vorbis_seek_func; callbacks.close_func = vorbis_close_func; callbacks.tell_func = vorbis_tell_func; audio->decoder_end_of_stream = false; if ((err = ov_open_callbacks(audio, &audio->oggvorbis_file, NULL, 0, callbacks)) < 0) { fprintf(stderr, "Error in ov_open_callbacks %i\n", err); return -1; } int bytes_read; int current_bitstream; char buffer[AUDIO_CHUNK_SIZE]; do { #ifdef __BIG_ENDIAN__ bytes_read = ov_read(&audio->oggvorbis_file, buffer, AUDIO_CHUNK_SIZE, 1, 2, 1, ¤t_bitstream); #else /* __LITTLE_ENDIAN__ */ bytes_read = ov_read(&audio->oggvorbis_file, buffer, AUDIO_CHUNK_SIZE, 0, 2, 1, ¤t_bitstream); #endif switch (bytes_read) { case OV_HOLE: case OV_EBADLINK: fprintf(stderr, "Error decoding vorbis stream\n"); goto vorbis_error; case 0: // End of file break; default: slimaudio_buffer_write(audio->output_buffer, buffer, bytes_read); } } while (bytes_read > 0); if ((err = ov_clear(&audio->oggvorbis_file)) < 0) { fprintf(stderr, "Error in ov_clear %i\n", err); return -1; } DEBUGF("slimaudio_decoder_vorbis_process: end\n"); return 0; vorbis_error: if ((err = ov_clear(&audio->oggvorbis_file)) < 0) { fprintf(stderr, "Error in ov_clear %i\n", err); return -1; } return -1; }
SoundBuffer* loadOggFile(const std::string &filepath) { int endian = 0; // 0 for Little-Endian, 1 for Big-Endian int bitStream; long bytes; char array[BUFFER_SIZE]; // Local fixed size array vorbis_info *pInfo; OggVorbis_File oggFile; // Do a dumb-ass static string copy for old versions of ov_fopen // because they expect a non-const char* char nonconst[10000]; snprintf(nonconst, 10000, "%s", filepath.c_str()); // Try opening the given file //if(ov_fopen(filepath.c_str(), &oggFile) != 0) if(ov_fopen(nonconst, &oggFile) != 0) { infostream<<"Audio: Error opening "<<filepath<<" for decoding"<<std::endl; return NULL; } SoundBuffer *snd = new SoundBuffer; // Get some information about the OGG file pInfo = ov_info(&oggFile, -1); // Check the number of channels... always use 16-bit samples if(pInfo->channels == 1) snd->format = AL_FORMAT_MONO16; else snd->format = AL_FORMAT_STEREO16; // The frequency of the sampling rate snd->freq = pInfo->rate; // Keep reading until all is read do { // Read up to a buffer's worth of decoded sound data bytes = ov_read(&oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream); if(bytes < 0) { ov_clear(&oggFile); infostream<<"Audio: Error decoding "<<filepath<<std::endl; return NULL; } // Append to end of buffer snd->buffer.insert(snd->buffer.end(), array, array + bytes); } while (bytes > 0); alGenBuffers(1, &snd->buffer_id); alBufferData(snd->buffer_id, snd->format, &(snd->buffer[0]), snd->buffer.size(), snd->freq); ALenum error = alGetError(); if(error != AL_NO_ERROR){ infostream<<"Audio: OpenAL error: "<<alErrorString(error) <<"preparing sound buffer"<<std::endl; } infostream<<"Audio file "<<filepath<<" loaded"<<std::endl; // Clean up! ov_clear(&oggFile); return snd; }
f_cnt_t SampleBuffer::decodeSampleOGGVorbis( const char * _f, int_sample_t * & _buf, ch_cnt_t & _channels, sample_rate_t & _samplerate ) { static ov_callbacks callbacks = { qfileReadCallback, qfileSeekCallback, qfileCloseCallback, qfileTellCallback } ; OggVorbis_File vf; f_cnt_t frames = 0; QFile * f = new QFile( _f ); if( f->open( QFile::ReadOnly ) == false ) { delete f; return 0; } int err = ov_open_callbacks( f, &vf, NULL, 0, callbacks ); if( err < 0 ) { switch( err ) { case OV_EREAD: printf( "SampleBuffer::decodeSampleOGGVorbis():" " media read error\n" ); break; case OV_ENOTVORBIS: /* printf( "SampleBuffer::decodeSampleOGGVorbis():" " not an Ogg Vorbis file\n" );*/ break; case OV_EVERSION: printf( "SampleBuffer::decodeSampleOGGVorbis():" " vorbis version mismatch\n" ); break; case OV_EBADHEADER: printf( "SampleBuffer::decodeSampleOGGVorbis():" " invalid Vorbis bitstream header\n" ); break; case OV_EFAULT: printf( "SampleBuffer::decodeSampleOgg(): " "internal logic fault\n" ); break; } delete f; return 0; } ov_pcm_seek( &vf, 0 ); _channels = ov_info( &vf, -1 )->channels; _samplerate = ov_info( &vf, -1 )->rate; ogg_int64_t total = ov_pcm_total( &vf, -1 ); _buf = new int_sample_t[total * _channels]; int bitstream = 0; long bytes_read = 0; do { bytes_read = ov_read( &vf, (char *) &_buf[frames * _channels], ( total - frames ) * _channels * BYTES_PER_INT_SAMPLE, isLittleEndian() ? 0 : 1, BYTES_PER_INT_SAMPLE, 1, &bitstream ); if( bytes_read < 0 ) { break; } frames += bytes_read / ( _channels * BYTES_PER_INT_SAMPLE ); } while( bytes_read != 0 && bitstream == 0 ); ov_clear( &vf ); // if buffer isn't empty, convert it to float and write it down if ( frames > 0 && _buf != NULL ) { convertIntToFloat ( _buf, frames, _channels); } return frames; }
SoundID Audio::addSound(const char *fileName, unsigned int flags){ Sound sound; // Clear error flag alGetError(); const char *ext = strrchr(fileName, '.') + 1; char str[256]; if (stricmp(ext, "ogg") == 0){ FILE *file = fopen(fileName, "rb"); if (file == NULL){ sprintf(str, "Couldn't open \"%s\"", fileName); ErrorMsg(str); return SOUND_NONE; } OggVorbis_File vf; memset(&vf, 0, sizeof(vf)); if (ov_open(file, &vf, NULL, 0) < 0){ fclose(file); sprintf(str, "\"%s\" is not an ogg file", fileName); ErrorMsg(str); return SOUND_NONE; } vorbis_info *vi = ov_info(&vf, -1); int nSamples = (uint) ov_pcm_total(&vf, -1); int nChannels = vi->channels; sound.format = nChannels == 1? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; sound.sampleRate = vi->rate; sound.size = nSamples * nChannels; sound.samples = new short[sound.size]; sound.size *= sizeof(short); int samplePos = 0; while (samplePos < sound.size){ char *dest = ((char *) sound.samples) + samplePos; int bitStream, readBytes = ov_read(&vf, dest, sound.size - samplePos, 0, 2, 1, &bitStream); if (readBytes <= 0) break; samplePos += readBytes; } ov_clear(&vf); } else { ALboolean al_bool; ALvoid *data; alutLoadWAVFile(fileName, &sound.format, &data, &sound.size, &sound.sampleRate, &al_bool); sound.samples = (short *) data; } alGenBuffers(1, &sound.buffer); alBufferData(sound.buffer, sound.format, sound.samples, sound.size, sound.sampleRate); if (alGetError() != AL_NO_ERROR){ alDeleteBuffers(1, &sound.buffer); sprintf(str, "Couldn't open \"%s\"", fileName); ErrorMsg(str); return SOUND_NONE; } return insertSound(sound); }
/* *callback(...) * * this procedure is called by the streaming server when it needs more PCM data * for internal buffering */ static void *callback(snd_stream_hnd_t hnd, int size, int * size_out) { #ifdef TIMING_TESTS int decoded_bytes = 0; uint32 s_s, s_ms, e_s, e_ms; #endif // printf("sndoggvorbis: callback requested %d bytes\n",size); /* Check if the callback requests more data than our buffer can hold */ if (size > BUF_SIZE) size = BUF_SIZE; #ifdef TIMING_TESTS timer_ms_gettime(&s_s, &s_ms); #endif /* Shift the last data the AICA driver took out of the PCM Buffer */ if (last_read > 0) { pcm_count -= last_read; if (pcm_count < 0) pcm_count=0; /* Don't underrun */ /* printf("memcpy(%08x, %08x, %d (%d - %d))\n", pcm_buffer, pcm_buffer+last_read, pcm_count-last_read, pcm_count, last_read); */ memcpy(pcm_buffer, pcm_buffer+last_read, pcm_count); pcm_ptr = pcm_buffer + pcm_count; } /* If our buffer has not enough data to fulfill the callback decode 4 KB * chunks until we have enough PCM samples buffered */ // printf("sndoggvorbis: fill buffer if not enough data\n"); long pcm_decoded = 0; while(pcm_count < size) { //int pcm_decoded = VorbisFile_decodePCMint8(v_headers, pcm_ptr, 4096); pcm_decoded = ov_read(&vf, pcm_ptr, 4096, ¤t_section); /* Are we at the end of the stream? If so and looping is enabled, then go ahead and seek back to the first. */ if (pcm_decoded == 0 && sndoggvorbis_loop) { /* Seek back */ if (ov_raw_seek(&vf, 0) < 0) { dbglog(DBG_ERROR, "sndoggvorbis: can't ov_raw_seek to the beginning!\n"); } else { /* Try again */ pcm_decoded = ov_read(&vf, pcm_ptr, 4096, ¤t_section); } } #ifdef TIMING_TESTS decoded_bytes += pcm_decoded; #endif // printf("pcm_decoded is %d\n", pcm_decoded); pcm_count += pcm_decoded; pcm_ptr += pcm_decoded; //if (pcm_decoded == 0 && check_for_reopen() < 0) // break; if (pcm_decoded == 0) break; } if (pcm_count > size) *size_out = size; else *size_out = pcm_count; /* Let the next callback know how many bytes the last callback grabbed */ last_read = *size_out; #ifdef TIMING_TESTS if (decoded_bytes != 0) { int t; timer_ms_gettime(&e_s, &e_ms); t = ((int)e_ms - (int)s_ms) + ((int)e_s - (int)s_s) * 1000; printf("%dms for %d bytes (%.2fms / byte)\n", t, decoded_bytes, t*1.0f/decoded_bytes); } #endif // printf("sndoggvorbis: callback: returning\n"); if (pcm_decoded == 0) return NULL; else return pcm_buffer; }
bool OggPlayer::OpenOgg( const char *filename ) { if (!bInitialized) return false; if (bFileOpened) Close(); FILE *f; f = fopen(filename, "rb"); if (!f) return false; ov_open(f, &vf, NULL, 0); // ok now the tricky part // the vorbis_info struct keeps the most of the interesting format info vorbis_info *vi = ov_info(&vf,-1); vorbis_comment *vc = ov_comment(&vf, 0); nLoopStart = 0; nLoopEnd = 0; if (vc != NULL) { for (int i = 0; i < ARRAYLEN(loop_start_tags); i++) { char *value = vorbis_comment_query(vc, loop_start_tags[i], 0); if (value != NULL) { nLoopStart = atoi(value); } } for (int i = 0; i < ARRAYLEN(loop_end_tags); i++) { char *value = vorbis_comment_query(vc, loop_end_tags[i], 0); if (value != NULL) { nLoopEnd = atoi(value); } } } if (nLoopEnd <= nLoopStart) { nLoopEnd = ov_pcm_total(&vf, -1); } // set the wave format WAVEFORMATEX wfm; memset(&wfm, 0, sizeof(wfm)); wfm.cbSize = sizeof(wfm); wfm.nChannels = vi->channels; wfm.wBitsPerSample = 16; // ogg vorbis is always 16 bit wfm.nSamplesPerSec = vi->rate; wfm.nAvgBytesPerSec = wfm.nSamplesPerSec*wfm.nChannels*2; wfm.nBlockAlign = 2*wfm.nChannels; wfm.wFormatTag = 1; // set up the buffer DSBUFFERDESC desc; desc.dwSize = sizeof(desc); desc.dwFlags = DSBCAPS_CTRLVOLUME; desc.lpwfxFormat = &wfm; desc.dwReserved = 0; desc.dwBufferBytes = BUFSIZE*2; pDS->CreateSoundBuffer(&desc, &pDSB, NULL ); // fill the buffer DWORD pos = 0; int sec = 0; int ret = 1; DWORD size = BUFSIZE*2; char *buf; pDSB->Lock(0, size, (LPVOID*)&buf, &size, NULL, NULL, DSBLOCK_ENTIREBUFFER); // now read in the bits while(ret && pos<size) { ret = ov_read(&vf, buf+pos, size-pos, 0, 2, 1, &sec); pos += ret; } pDSB->Unlock( buf, size, NULL, NULL ); nCurSection = nLastSection = 0; return bFileOpened = true; }