/** * @brief Loads an ogg file from a tested format if possible. * * @param snd Sound to load ogg into. * @param vf Vorbisfile containing the song. */ static int sound_al_loadOgg( alSound *snd, OggVorbis_File *vf ) { int ret; long i; int section; vorbis_info *info; ALenum format; ogg_int64_t len; char *buf; /* Finish opening the file. */ ret = ov_test_open(vf); if (ret) { WARN("Failed to finish loading OGG file: %s", vorbis_getErr(ret) ); return -1; } /* Get file information. */ info = ov_info( vf, -1 ); format = (info->channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16; len = ov_pcm_total( vf, -1 ) * info->channels * 2; /* Allocate memory. */ buf = malloc( len ); /* Fill buffer. */ i = 0; while (i < len) { /* Fill buffer with data in the 16 bit signed samples format. */ i += ov_read( vf, &buf[i], len-i, VORBIS_ENDIAN, 2, 1, §ion ); } soundLock(); /* Create new buffer. */ alGenBuffers( 1, &snd->u.al.buf ); /* Put into buffer. */ alBufferData( snd->u.al.buf, format, buf, len, info->rate ); soundUnlock(); /* Clean up. */ free(buf); ov_clear(vf); return 0; }
void Sound::Impl::PlaySound(const boost::filesystem::path& path, bool is_ui_sound/* = false*/) { if (!m_initialized || !GetOptionsDB().Get<bool>("UI.sound.enabled") || (is_ui_sound && UISoundsTemporarilyDisabled())) return; std::string filename = PathString(path); ALuint current_buffer; ALenum source_state; ALsizei ogg_freq; FILE *file = nullptr; int m_i; bool found_buffer = false; bool found_source = false; #ifdef FREEORION_WIN32 ov_callbacks callbacks = { (size_t (*)(void *, size_t, size_t, void *)) fread, (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, (int (*)(void *)) fclose, (long (*)(void *)) ftell }; #endif if (alcGetCurrentContext()) { /* First check if the sound data of the file we want to play is already buffered somewhere */ std::map<std::string, ALuint>::iterator it = m_buffers.find(filename); if (it != m_buffers.end()) { current_buffer = it->second; found_buffer = true; } else { if ((file = fopen(filename.c_str(), "rb")) != nullptr) { // make sure we CAN open it OggVorbis_File ogg_file; vorbis_info *vorbis_info; ALenum ogg_format; #ifdef FREEORION_WIN32 if (!(ov_test_callbacks(file, &ogg_file, nullptr, 0, callbacks))) // check if it's a proper ogg #else if (!(ov_test(file, &ogg_file, nullptr, 0))) // check if it's a proper ogg #endif { ov_test_open(&ogg_file); // it is, now fully open the file /* now we need to take some info we will need later */ vorbis_info = ov_info(&ogg_file, -1); if (vorbis_info->channels == 1) ogg_format = AL_FORMAT_MONO16; else ogg_format = AL_FORMAT_STEREO16; ogg_freq = vorbis_info->rate; ogg_int64_t byte_size = ov_pcm_total(&ogg_file, -1) * vorbis_info->channels * 2; if (byte_size <= 1024 * 1024 * 1024) { /* fill up the buffers and queue them up for the first time */ ALuint sound_handle; alGenBuffers(1, &sound_handle); int loop = 0; RefillBuffer(&ogg_file, ogg_format, ogg_freq, sound_handle, byte_size, loop); current_buffer = sound_handle; found_buffer = true; m_buffers.insert(std::make_pair(filename, sound_handle)); } else { ErrorLogger() << "PlaySound: unable to open file " << filename.c_str() << " too big to buffer. Aborting\n"; } ov_clear(&ogg_file); } else { ErrorLogger() << "PlaySound: unable to open file " << filename.c_str() << " possibly not a .ogg vorbis file. Aborting\n"; } } } if (found_buffer) { /* Now that we have the buffer, we need to find a source to send it to */ for (m_i = 1; m_i < NUM_SOURCES; ++m_i) { // as we're playing sounds we start at 1. 0 is reserved for music alGetSourcei(m_sources[m_i], AL_SOURCE_STATE, &source_state); if ((source_state != AL_PLAYING) && (source_state != AL_PAUSED)) { found_source = true; alSourcei(m_sources[m_i], AL_BUFFER, current_buffer); alSourcePlay(m_sources[m_i]); break; // so that the sound won't block all the sources } } if (!found_source) ErrorLogger() << "PlaySound: Could not find aviable source - playback aborted\n"; } source_state = alGetError(); if (source_state != AL_NONE) ErrorLogger() << "PlaySound: OpenAL ERROR: " << alGetString(source_state); /* it's important to check for errors, as some functions won't work properly if * they're called when there is a unchecked previous error. */ } }
void Sound::Impl::PlayMusic(const boost::filesystem::path& path, int loops /* = 0*/) { if (!m_initialized) return; ALenum m_openal_error; std::string filename = PathString(path); FILE* m_f = nullptr; vorbis_info* vorbis_info; m_music_loops = 0; #ifdef FREEORION_WIN32 ov_callbacks callbacks = { (size_t (*)(void *, size_t, size_t, void *)) fread, (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, (int (*)(void *)) fclose, (long (*)(void *)) ftell }; #endif if (alcGetCurrentContext()) { if (m_music_name.size() > 0) StopMusic(); if ((m_f = fopen(filename.c_str(), "rb")) != nullptr) // make sure we CAN open it { #ifdef FREEORION_WIN32 if (!(ov_test_callbacks(m_f, &m_ogg_file, nullptr, 0, callbacks))) // check if it's a proper ogg #else if (!(ov_test(m_f, &m_ogg_file, nullptr, 0))) // check if it's a proper ogg #endif { ov_test_open(&m_ogg_file); // it is, now fully open the file /* now we need to take some info we will need later */ vorbis_info = ov_info(&m_ogg_file, -1); if (vorbis_info->channels == 1) m_ogg_format = AL_FORMAT_MONO16; else m_ogg_format = AL_FORMAT_STEREO16; m_ogg_freq = vorbis_info->rate; m_music_loops = loops; /* fill up the buffers and queue them up for the first time */ if (!RefillBuffer(&m_ogg_file, m_ogg_format, m_ogg_freq, m_music_buffers[0], BUFFER_SIZE, m_music_loops)) { alSourceQueueBuffers(m_sources[0], 1, &m_music_buffers[0]); // queue up the buffer if we manage to fill it if (!RefillBuffer(&m_ogg_file, m_ogg_format, m_ogg_freq, m_music_buffers[1], BUFFER_SIZE, m_music_loops)) { alSourceQueueBuffers(m_sources[0], 1, &m_music_buffers[1]); m_music_name = filename; // yup, we're playing something that takes up more than 2 buffers } else { m_music_name.clear(); // m_music_name.clear() must always be called before ov_clear. Otherwise } alSourcePlay(m_sources[0]); // play if at least one buffer is queued } else { m_music_name.clear(); // m_music_name.clear() must always be called before ov_clear. Otherwise } } else { ErrorLogger() << "PlayMusic: unable to open file " << filename.c_str() << " possibly not a .ogg vorbis file. Aborting\n"; m_music_name.clear(); //just in case ov_clear(&m_ogg_file); } } else ErrorLogger() << "PlayMusic: unable to open file " << filename.c_str() << " I/O Error. Aborting\n"; } m_openal_error = alGetError(); if (m_openal_error != AL_NONE) ErrorLogger() << "PlayMusic: OpenAL ERROR: " << alGetString(m_openal_error); }
void CreateVorbisStream(MFAudioStream *pStream, const char *pFilename) { MFCALLSTACK; MFVorbisStream *pVS = (MFVorbisStream*)MFHeap_Alloc(sizeof(MFVorbisStream)); pStream->pStreamData = pVS; // open vorbis file MFFile* hFile = MFFileSystem_Open(pFilename); if(!hFile) return; // attempt to cache the vorbis stream MFOpenDataCachedFile cachedOpen; cachedOpen.cbSize = sizeof(MFOpenDataCachedFile); cachedOpen.openFlags = MFOF_Read | MFOF_Binary | MFOF_Cached_CleanupBaseFile; cachedOpen.maxCacheSize = 256*1024; // 256k cache for vorbis stream should be heaps!! cachedOpen.pBaseFile = hFile; MFFile *pCachedFile = MFFile_Open(MFFileSystem_GetInternalFileSystemHandle(MFFSH_CachedFileSystem), &cachedOpen); if(pCachedFile) hFile = pCachedFile; // setup vorbis read callbacks ov_callbacks callbacks; callbacks.read_func = MFFile_StdRead; callbacks.seek_func = MFSound_VorbisSeek; callbacks.close_func = MFFile_StdClose; callbacks.tell_func = MFFile_StdTell; // open vorbis file if(ov_test_callbacks(hFile, &pVS->vorbisFile, NULL, 0, callbacks)) { MFDebug_Assert(false, "Not a vorbis file."); MFHeap_Free(pVS); return; } ov_test_open(&pVS->vorbisFile); // get vorbis file info pVS->pInfo = ov_info(&pVS->vorbisFile, -1); #if defined(VORBIS_TREMOR) // pStream->trackLength = (float)ov_pcm_total(&pVS->vorbisFile, -1) / (float)pVS->pInfo->rate; pStream->trackLength = 1000.0f; #else pStream->trackLength = (float)ov_time_total(&pVS->vorbisFile, -1); #endif // fill out the stream info pStream->streamInfo.sampleRate = pVS->pInfo->rate; pStream->streamInfo.channels = pVS->pInfo->channels; pStream->streamInfo.bitsPerSample = 16; pStream->streamInfo.bufferLength = pVS->pInfo->rate; // read the vorbis comment data pVS->pComment = ov_comment(&pVS->vorbisFile, -1); if(pVS->pComment) { const char *pTitle = vorbis_comment_query(pVS->pComment, "TITLE", 0); const char *pArtist = vorbis_comment_query(pVS->pComment, "ALBUM", 0); const char *pAlbum = vorbis_comment_query(pVS->pComment, "ARTIST", 0); const char *pGenre = vorbis_comment_query(pVS->pComment, "GENRE", 0); if(pTitle) MFString_CopyN(pStream->streamInfo.songName, pTitle, sizeof(pStream->streamInfo.songName)-1); if(pArtist) MFString_CopyN(pStream->streamInfo.artistName, pArtist, sizeof(pStream->streamInfo.artistName)-1); if(pAlbum) MFString_CopyN(pStream->streamInfo.albumName, pAlbum, sizeof(pStream->streamInfo.albumName)-1); if(pGenre) MFString_CopyN(pStream->streamInfo.genre, pGenre, sizeof(pStream->streamInfo.genre)-1); } }