diff --git a/Bitstream Vera License.txt b/Bitstream Vera License.txt new file mode 100644 index 000000000..2b37cc1df --- /dev/null +++ b/Bitstream Vera License.txt @@ -0,0 +1,123 @@ +Bitstream Vera Fonts Copyright + +The fonts have a generous copyright, allowing derivative works (as +long as "Bitstream" or "Vera" are not in the names), and full +redistribution (so long as they are not *sold* by themselves). They +can be be bundled, redistributed and sold with any software. + +The fonts are distributed under the following copyright: + +Copyright +========= + +Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream +Vera is a trademark of Bitstream, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the fonts accompanying this license ("Fonts") and associated +documentation files (the "Font Software"), to reproduce and distribute +the Font Software, including without limitation the rights to use, +copy, merge, publish, distribute, and/or sell copies of the Font +Software, and to permit persons to whom the Font Software is furnished +to do so, subject to the following conditions: + +The above copyright and trademark notices and this permission notice +shall be included in all copies of one or more of the Font Software +typefaces. + +The Font Software may be modified, altered, or added to, and in +particular the designs of glyphs or characters in the Fonts may be +modified and additional glyphs or characters may be added to the +Fonts, only if the fonts are renamed to names not containing either +the words "Bitstream" or the word "Vera". + +This License becomes null and void to the extent applicable to Fonts +or Font Software that has been modified and is distributed under the +"Bitstream Vera" names. + +The Font Software may be sold as part of a larger software package but +no copy of one or more of the Font Software typefaces may be sold by +itself. + +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL +BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, +OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT +SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. + +Except as contained in this notice, the names of Gnome, the Gnome +Foundation, and Bitstream Inc., shall not be used in advertising or +otherwise to promote the sale, use or other dealings in this Font +Software without prior written authorization from the Gnome Foundation +or Bitstream Inc., respectively. For further information, contact: +fonts at gnome dot org. + +Copyright FAQ +============= + + 1. I don't understand the resale restriction... What gives? + + Bitstream is giving away these fonts, but wishes to ensure its + competitors can't just drop the fonts as is into a font sale system + and sell them as is. It seems fair that if Bitstream can't make money + from the Bitstream Vera fonts, their competitors should not be able to + do so either. You can sell the fonts as part of any software package, + however. + + 2. I want to package these fonts separately for distribution and + sale as part of a larger software package or system. Can I do so? + + Yes. A RPM or Debian package is a "larger software package" to begin + with, and you aren't selling them independently by themselves. + See 1. above. + + 3. Are derivative works allowed? + Yes! + + 4. Can I change or add to the font(s)? + Yes, but you must change the name(s) of the font(s). + + 5. Under what terms are derivative works allowed? + + You must change the name(s) of the fonts. This is to ensure the + quality of the fonts, both to protect Bitstream and Gnome. We want to + ensure that if an application has opened a font specifically of these + names, it gets what it expects (though of course, using fontconfig, + substitutions could still could have occurred during font + opening). You must include the Bitstream copyright. Additional + copyrights can be added, as per copyright law. Happy Font Hacking! + + 6. If I have improvements for Bitstream Vera, is it possible they might get + adopted in future versions? + + Yes. The contract between the Gnome Foundation and Bitstream has + provisions for working with Bitstream to ensure quality additions to + the Bitstream Vera font family. Please contact us if you have such + additions. Note, that in general, we will want such additions for the + entire family, not just a single font, and that you'll have to keep + both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add + glyphs to the font, they must be stylistically in keeping with Vera's + design. Vera cannot become a "ransom note" font. Jim Lyles will be + providing a document describing the design elements used in Vera, as a + guide and aid for people interested in contributing to Vera. + + 7. I want to sell a software package that uses these fonts: Can I do so? + + Sure. Bundle the fonts with your software and sell your software + with the fonts. That is the intent of the copyright. + + 8. If applications have built the names "Bitstream Vera" into them, + can I override this somehow to use fonts of my choosing? + + This depends on exact details of the software. Most open source + systems and software (e.g., Gnome, KDE, etc.) are now converting to + use fontconfig (see www.fontconfig.org) to handle font configuration, + selection and substitution; it has provisions for overriding font + names and subsituting alternatives. An example is provided by the + supplied local.conf file, which chooses the family Bitstream Vera for + "sans", "serif" and "monospace". Other software (e.g., the XFree86 + core server) has other mechanisms for font substitution. diff --git a/CMakeLists.txt b/CMakeLists.txt index a85880529..21003d9ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,7 +30,6 @@ configure_file ("${OpenMW_SOURCE_DIR}/Docs/mainpage.hpp.cmake" "${OpenMW_SOURCE_ option(OGRE_STATIC "Link static build of Ogre and Ogre Plugins into the binaries" FALSE) # Sound source selection -option(USE_AUDIERE "use Audiere for sound" OFF) option(USE_FFMPEG "use ffmpeg for sound" OFF) option(USE_MPG123 "use mpg123 + libsndfile for sound" ON) @@ -120,52 +119,31 @@ set(OENGINE_BULLET ${LIBDIR}/openengine/bullet/BulletShapeLoader.h ) -# Sound setup -if (USE_AUDIERE) - set(MANGLE_SOUND_OUTPUT - ${LIBDIR}/mangle/sound/sources/audiere_source.cpp - ${LIBDIR}/mangle/sound/sources/sample_reader.cpp - ${LIBDIR}/mangle/stream/clients/audiere_file.cpp) - find_package(Audiere REQUIRED) - set(SOUND_INPUT_INCLUDES ${AUDIERE_INCLUDE_DIR}) - set(SOUND_INPUT_LIBRARY ${AUDIERE_LIBRARY}) - set(SOUND_DEFINE -DOPENMW_USE_AUDIERE) -endif (USE_AUDIERE) +set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_BULLET}) +source_group(libs\\openengine FILES ${OENGINE_ALL}) + +set(OPENMW_LIBS ${MANGLE_ALL} ${OENGINE_ALL}) +set(OPENMW_LIBS_HEADER) +# Sound setup +set(SOUND_INPUT_INCLUDES "") +set(SOUND_INPUT_LIBRARY "") +set(SOUND_DEFINE "") if (USE_FFMPEG) - set(MANGLE_SOUND_OUTPUT - ${LIBDIR}/mangle/sound/sources/ffmpeg_source.cpp) find_package(FFMPEG REQUIRED) - set(SOUND_INPUT_INCLUDES ${FFMPEG_INCLUDE_DIR}) - set(SOUND_INPUT_LIBRARY ${FFMPEG_LIBRARIES}) - set(SOUND_DEFINE -DOPENMW_USE_FFMPEG) + set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${FFMPEG_INCLUDE_DIR}) + set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${FFMPEG_LIBRARIES}) + set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_FFMPEG) endif (USE_FFMPEG) if (USE_MPG123) - set(MANGLE_SOUND_OUTPUT - ${LIBDIR}/mangle/sound/sources/mpg123_source.cpp - ${LIBDIR}/mangle/sound/sources/libsndfile.cpp - ${LIBDIR}/mangle/sound/sources/sample_reader.cpp) find_package(MPG123 REQUIRED) find_package(SNDFILE REQUIRED) - set(SOUND_INPUT_INCLUDES ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR}) - set(SOUND_INPUT_LIBRARY ${MPG123_LIBRARY} ${SNDFILE_LIBRARY}) - set(SOUND_DEFINE -DOPENMW_USE_MPG123) + set(SOUND_INPUT_INCLUDES ${SOUND_INPUT_INCLUDES} ${MPG123_INCLUDE_DIR} ${SNDFILE_INCLUDE_DIR}) + set(SOUND_INPUT_LIBRARY ${SOUND_INPUT_LIBRARY} ${MPG123_LIBRARY} ${SNDFILE_LIBRARY}) + set(SOUND_DEFINE ${SOUND_DEFINE} -DOPENMW_USE_MPG123) endif (USE_MPG123) -set(OENGINE_SOUND - # Mangle and OEngine sound files are sort of intertwined, so put - # them together here - ${LIBDIR}/openengine/sound/sndmanager.cpp - ${LIBDIR}/mangle/sound/outputs/openal_out.cpp - ${MANGLE_SOUND_OUTPUT} -) -set(OENGINE_ALL ${OENGINE_OGRE} ${OENGINE_GUI} ${OENGINE_SOUND} ${OENGINE_BULLET}) -source_group(libs\\openengine FILES ${OENGINE_ALL}) - -set(OPENMW_LIBS ${MANGLE_ALL} ${OENGINE_ALL}) -set(OPENMW_LIBS_HEADER) - # Platform specific if (WIN32) set(PLATFORM_INCLUDE_DIR "platform") diff --git a/OFL.txt b/OFL.txt new file mode 100644 index 000000000..043e85e83 --- /dev/null +++ b/OFL.txt @@ -0,0 +1,93 @@ +Copyright (c) 2010, 2011 Georg Duffner (http://www.georgduffner.at) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/apps/launcher/maindialog.cpp b/apps/launcher/maindialog.cpp index 49c0bd960..ef9cfa851 100644 --- a/apps/launcher/maindialog.cpp +++ b/apps/launcher/maindialog.cpp @@ -45,9 +45,28 @@ MainDialog::MainDialog() setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint); setMinimumSize(QSize(575, 575)); + // Install the stylesheet font + QFile file; + QFontDatabase fontDatabase; + + const QStringList fonts = fontDatabase.families(); + + // Check if the font is installed + if (!fonts.contains("EB Garamond")) { + + QString font = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); + file.setFileName(font); + + if (!file.exists()) { + font = QString::fromStdString((mCfgMgr.getLocalPath() / "resources/mygui/EBGaramond-Regular.ttf").string()); + } + + fontDatabase.addApplicationFont(font); + } + // Load the stylesheet QString config = QString::fromStdString((mCfgMgr.getGlobalDataPath() / "resources/launcher.qss").string()); - QFile file(config); + file.setFileName(config); if (!file.exists()) { file.setFileName(QString::fromStdString((mCfgMgr.getLocalPath() / "launcher.qss").string())); diff --git a/apps/launcher/resources/images/openmw-header.png b/apps/launcher/resources/images/openmw-header.png index a168d4d2a..a2ffab68b 100644 Binary files a/apps/launcher/resources/images/openmw-header.png and b/apps/launcher/resources/images/openmw-header.png differ diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 8dbcd5e6c..3f55e0c88 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -39,7 +39,7 @@ add_openmw_dir (mwscript ) add_openmw_dir (mwsound - soundmanager + soundmanager openal_output mpgsnd_decoder ffmpeg_decoder ) add_openmw_dir (mwworld diff --git a/apps/openmw/engine.cpp b/apps/openmw/engine.cpp index 89068ce53..5e49ae2f7 100644 --- a/apps/openmw/engine.cpp +++ b/apps/openmw/engine.cpp @@ -117,11 +117,7 @@ bool OMW::Engine::frameRenderingQueued (const Ogre::FrameEvent& evt) // sound if (mUseSound) - { - mEnvironment.mSoundManager->playPlaylist(); - mEnvironment.mSoundManager->update (evt.timeSinceLastFrame); - } // update GUI Ogre::RenderWindow* window = mOgre->getWindow(); @@ -337,10 +333,7 @@ void OMW::Engine::go() mExtensions, mFpsLevel, mNewGame, mOgre, mCfgMgr.getLogPath().string() + std::string("/")); // Create sound system - mEnvironment.mSoundManager = new MWSound::SoundManager(mOgre->getRoot(), - mOgre->getCamera(), - mDataDirs, - mUseSound, mFSStrict, mEnvironment); + mEnvironment.mSoundManager = new MWSound::SoundManager(mUseSound, mEnvironment); // Create script system mScriptContext = new MWScript::CompilerContext (MWScript::CompilerContext::Type_Full, diff --git a/apps/openmw/mwgui/layouts.cpp b/apps/openmw/mwgui/layouts.cpp index 5c5a977d3..9c49c62ac 100644 --- a/apps/openmw/mwgui/layouts.cpp +++ b/apps/openmw/mwgui/layouts.cpp @@ -202,6 +202,7 @@ void MapWindow::setVisible(bool b) void MapWindow::setCellName(const std::string& cellName) { static_cast(mMainWidget)->setCaption(cellName); + adjustWindowCaption(); } void MapWindow::setPlayerPos(const float x, const float y) diff --git a/apps/openmw/mwsound/ffmpeg_decoder.cpp b/apps/openmw/mwsound/ffmpeg_decoder.cpp new file mode 100644 index 000000000..9298bf848 --- /dev/null +++ b/apps/openmw/mwsound/ffmpeg_decoder.cpp @@ -0,0 +1,407 @@ +#ifdef OPENMW_USE_FFMPEG + +#include "ffmpeg_decoder.hpp" + + +namespace MWSound +{ + +static void fail(const std::string &msg) +{ throw std::runtime_error("FFmpeg exception: "+msg); } + + +struct PacketList { + AVPacket pkt; + PacketList *next; +}; + +struct FFmpeg_Decoder::MyStream { + AVCodecContext *mCodecCtx; + int mStreamIdx; + + PacketList *mPackets; + + char *mDecodedData; + size_t mDecodedDataSize; + + FFmpeg_Decoder *mParent; + + void clearPackets(); + void *getAVAudioData(size_t *length); + size_t readAVAudioData(void *data, size_t length); +}; + + +int FFmpeg_Decoder::readPacket(void *user_data, uint8_t *buf, int buf_size) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->read(buf, buf_size); +} + +int FFmpeg_Decoder::writePacket(void *user_data, uint8_t *buf, int buf_size) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->write(buf, buf_size); +} + +int64_t FFmpeg_Decoder::seek(void *user_data, int64_t offset, int whence) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + + whence &= ~AVSEEK_FORCE; + if(whence == AVSEEK_SIZE) + return stream->size(); + if(whence == SEEK_SET) + stream->seek(offset); + else if(whence == SEEK_CUR) + stream->seek(stream->tell()+offset); + else if(whence == SEEK_END) + stream->seek(stream->size()+offset); + else + return -1; + + return stream->tell(); +} + + +/* Used by getAV*Data to search for more compressed data, and buffer it in the + * correct stream. It won't buffer data for streams that the app doesn't have a + * handle for. */ +bool FFmpeg_Decoder::getNextPacket(int streamidx) +{ + PacketList *packet; + + packet = (PacketList*)av_malloc(sizeof(*packet)); + packet->next = NULL; + +next_packet: + while(av_read_frame(mFormatCtx, &packet->pkt) >= 0) + { + std::vector::iterator iter = mStreams.begin(); + + /* Check each stream the user has a handle for, looking for the one + * this packet belongs to */ + while(iter != mStreams.end()) + { + if((*iter)->mStreamIdx == packet->pkt.stream_index) + { + PacketList **last; + + last = &(*iter)->mPackets; + while(*last != NULL) + last = &(*last)->next; + + *last = packet; + if((*iter)->mStreamIdx == streamidx) + return true; + + packet = (PacketList*)av_malloc(sizeof(*packet)); + packet->next = NULL; + goto next_packet; + } + iter++; + } + /* Free the packet and look for another */ + av_free_packet(&packet->pkt); + } + av_free(packet); + + return false; +} + +void FFmpeg_Decoder::MyStream::clearPackets() +{ + while(mPackets) + { + PacketList *self = mPackets; + mPackets = self->next; + + av_free_packet(&self->pkt); + av_free(self); + } +} + +void *FFmpeg_Decoder::MyStream::getAVAudioData(size_t *length) +{ + int size; + int len; + + if(length) *length = 0; + if(mCodecCtx->codec_type != AVMEDIA_TYPE_AUDIO) + return NULL; + + mDecodedDataSize = 0; + +next_packet: + if(!mPackets && !mParent->getNextPacket(mStreamIdx)) + return NULL; + + /* Decode some data, and check for errors */ + size = AVCODEC_MAX_AUDIO_FRAME_SIZE; + while((len=avcodec_decode_audio3(mCodecCtx, (int16_t*)mDecodedData, &size, + &mPackets->pkt)) == 0) + { + PacketList *self; + + if(size > 0) + break; + + /* Packet went unread and no data was given? Drop it and try the next, + * I guess... */ + self = mPackets; + mPackets = self->next; + + av_free_packet(&self->pkt); + av_free(self); + + if(!mPackets) + goto next_packet; + + size = AVCODEC_MAX_AUDIO_FRAME_SIZE; + } + + if(len < 0) + return NULL; + + if(len < mPackets->pkt.size) + { + /* Move the unread data to the front and clear the end bits */ + int remaining = mPackets->pkt.size - len; + memmove(mPackets->pkt.data, &mPackets->pkt.data[len], remaining); + memset(&mPackets->pkt.data[remaining], 0, mPackets->pkt.size - remaining); + mPackets->pkt.size -= len; + } + else + { + PacketList *self; + + self = mPackets; + mPackets = self->next; + + av_free_packet(&self->pkt); + av_free(self); + } + + if(size == 0) + goto next_packet; + + /* Set the output buffer size */ + mDecodedDataSize = size; + if(length) *length = mDecodedDataSize; + + return mDecodedData; +} + +size_t FFmpeg_Decoder::MyStream::readAVAudioData(void *data, size_t length) +{ + size_t dec = 0; + + while(dec < length) + { + /* If there's no decoded data, find some */ + if(mDecodedDataSize == 0) + { + if(getAVAudioData(NULL) == NULL) + break; + } + + if(mDecodedDataSize > 0) + { + /* Get the amount of bytes remaining to be written, and clamp to + * the amount of decoded data we have */ + size_t rem = length-dec; + if(rem > mDecodedDataSize) + rem = mDecodedDataSize; + + /* Copy the data to the app's buffer and increment */ + if(data != NULL) + { + memcpy(data, mDecodedData, rem); + data = (char*)data + rem; + } + dec += rem; + + /* If there's any decoded data left, move it to the front of the + * buffer for next time */ + if(rem < mDecodedDataSize) + memmove(mDecodedData, &mDecodedData[rem], mDecodedDataSize - rem); + mDecodedDataSize -= rem; + } + } + + /* Return the number of bytes we were able to get */ + return dec; +} + + + +void FFmpeg_Decoder::open(const std::string &fname) +{ + close(); + mDataStream = mResourceMgr.openResource(fname); + + if((mFormatCtx=avformat_alloc_context()) == NULL) + fail("Failed to allocate context"); + + mFormatCtx->pb = avio_alloc_context(NULL, 0, 0, this, readPacket, writePacket, seek); + if(!mFormatCtx->pb || avformat_open_input(&mFormatCtx, fname.c_str(), NULL, NULL) != 0) + { + avformat_free_context(mFormatCtx); + mFormatCtx = NULL; + fail("Failed to allocate input stream"); + } + + try + { + if(avformat_find_stream_info(mFormatCtx, NULL) < 0) + fail("Failed to find stream info in "+fname); + + for(size_t j = 0;j < mFormatCtx->nb_streams;j++) + { + if(mFormatCtx->streams[j]->codec->codec_type == AVMEDIA_TYPE_AUDIO) + { + std::auto_ptr stream(new MyStream); + stream->mCodecCtx = mFormatCtx->streams[j]->codec; + stream->mStreamIdx = j; + stream->mPackets = NULL; + + AVCodec *codec = avcodec_find_decoder(stream->mCodecCtx->codec_id); + if(!codec) + { + std::stringstream ss("No codec found for id "); + ss << stream->mCodecCtx->codec_id; + fail(ss.str()); + } + if(avcodec_open(stream->mCodecCtx, codec) < 0) + fail("Failed to open audio codec " + std::string(codec->long_name)); + + stream->mDecodedData = (char*)av_malloc(AVCODEC_MAX_AUDIO_FRAME_SIZE); + stream->mDecodedDataSize = 0; + + stream->mParent = this; + mStreams.push_back(stream.release()); + break; + } + } + if(mStreams.empty()) + fail("No audio streams in "+fname); + } + catch(std::exception &e) + { + av_close_input_file(mFormatCtx); + mFormatCtx = NULL; + throw; + } +} + +void FFmpeg_Decoder::close() +{ + while(!mStreams.empty()) + { + MyStream *stream = mStreams.front(); + + stream->clearPackets(); + avcodec_close(stream->mCodecCtx); + av_free(stream->mDecodedData); + delete stream; + + mStreams.erase(mStreams.begin()); + } + if(mFormatCtx) + av_close_input_file(mFormatCtx); + mFormatCtx = NULL; + + mDataStream.setNull(); +} + +void FFmpeg_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) +{ + if(mStreams.empty()) + fail("No audio stream info"); + + MyStream *stream = mStreams[0]; + if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_U8) + *type = SampleType_UInt8; + else if(stream->mCodecCtx->sample_fmt == AV_SAMPLE_FMT_S16) + *type = SampleType_Int16; + else + fail(std::string("Unsupported sample format: ")+ + av_get_sample_fmt_name(stream->mCodecCtx->sample_fmt)); + + if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_MONO) + *chans = ChannelConfig_Mono; + else if(stream->mCodecCtx->channel_layout == AV_CH_LAYOUT_STEREO) + *chans = ChannelConfig_Stereo; + else if(stream->mCodecCtx->channel_layout == 0) + { + /* Unknown channel layout. Try to guess. */ + if(stream->mCodecCtx->channels == 1) + *chans = ChannelConfig_Mono; + else if(stream->mCodecCtx->channels == 2) + *chans = ChannelConfig_Stereo; + else + { + std::stringstream sstr("Unsupported raw channel count: "); + sstr << stream->mCodecCtx->channels; + fail(sstr.str()); + } + } + else + { + char str[1024]; + av_get_channel_layout_string(str, sizeof(str), stream->mCodecCtx->channels, + stream->mCodecCtx->channel_layout); + fail(std::string("Unsupported channel layout: ")+str); + } + + *samplerate = stream->mCodecCtx->sample_rate; +} + +size_t FFmpeg_Decoder::read(char *buffer, size_t bytes) +{ + if(mStreams.empty()) + fail("No audio streams"); + + return mStreams.front()->readAVAudioData(buffer, bytes); +} + +void FFmpeg_Decoder::readAll(std::vector &output) +{ + if(mStreams.empty()) + fail("No audio streams"); + MyStream *stream = mStreams.front(); + char *inbuf; + size_t got; + + while((inbuf=(char*)stream->getAVAudioData(&got)) != NULL && got > 0) + output.insert(output.end(), inbuf, inbuf+got); +} + +void FFmpeg_Decoder::rewind() +{ + av_seek_frame(mFormatCtx, -1, 0, 0); + std::for_each(mStreams.begin(), mStreams.end(), std::mem_fun(&MyStream::clearPackets)); +} + +FFmpeg_Decoder::FFmpeg_Decoder() : mFormatCtx(NULL) +{ + static bool done_init = false; + + /* We need to make sure ffmpeg is initialized. Optionally silence warning + * output from the lib */ + if(!done_init) + { + av_register_all(); + av_log_set_level(AV_LOG_ERROR); + done_init = true; + } +} + +FFmpeg_Decoder::~FFmpeg_Decoder() +{ + close(); +} + +} + +#endif diff --git a/apps/openmw/mwsound/ffmpeg_decoder.hpp b/apps/openmw/mwsound/ffmpeg_decoder.hpp new file mode 100644 index 000000000..4344397c7 --- /dev/null +++ b/apps/openmw/mwsound/ffmpeg_decoder.hpp @@ -0,0 +1,59 @@ +#ifndef GAME_SOUND_FFMPEG_DECODER_H +#define GAME_SOUND_FFMPEG_DECODER_H + +#include + +// FIXME: This can't be right? The headers refuse to build without UINT64_C, +// which only gets defined in stdint.h in either C99 mode or with this macro +// defined... +#define __STDC_CONSTANT_MACROS +#include +extern "C" +{ +#include +#include +} + +#include "sound_decoder.hpp" + + +namespace MWSound +{ + class FFmpeg_Decoder : public Sound_Decoder + { + AVFormatContext *mFormatCtx; + + struct MyStream; + std::vector mStreams; + + bool getNextPacket(int streamidx); + + Ogre::DataStreamPtr mDataStream; + static int readPacket(void *user_data, uint8_t *buf, int buf_size); + static int writePacket(void *user_data, uint8_t *buf, int buf_size); + static int64_t seek(void *user_data, int64_t offset, int whence); + + virtual void open(const std::string &fname); + virtual void close(); + + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); + + virtual size_t read(char *buffer, size_t bytes); + virtual void readAll(std::vector &output); + virtual void rewind(); + + FFmpeg_Decoder& operator=(const FFmpeg_Decoder &rhs); + FFmpeg_Decoder(const FFmpeg_Decoder &rhs); + + FFmpeg_Decoder(); + public: + virtual ~FFmpeg_Decoder(); + + friend class SoundManager; + }; +#ifndef DEFAULT_DECODER +#define DEFAULT_DECODER (::MWSound::FFmpeg_Decoder) +#endif +}; + +#endif diff --git a/apps/openmw/mwsound/mpgsnd_decoder.cpp b/apps/openmw/mwsound/mpgsnd_decoder.cpp new file mode 100644 index 000000000..f576833a8 --- /dev/null +++ b/apps/openmw/mwsound/mpgsnd_decoder.cpp @@ -0,0 +1,231 @@ +#ifdef OPENMW_USE_MPG123 + +#include +#include + +#include "mpgsnd_decoder.hpp" + + +static void fail(const std::string &msg) +{ throw std::runtime_error("MpgSnd exception: "+msg); } + +namespace MWSound +{ + +// +// libSndFile io callbacks +// +sf_count_t MpgSnd_Decoder::ogresf_get_filelen(void *user_data) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->size(); +} + +sf_count_t MpgSnd_Decoder::ogresf_seek(sf_count_t offset, int whence, void *user_data) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + + if(whence == SEEK_CUR) + stream->seek(stream->tell()+offset); + else if(whence == SEEK_SET) + stream->seek(offset); + else if(whence == SEEK_END) + stream->seek(stream->size()+offset); + else + return -1; + + return stream->tell(); +} + +sf_count_t MpgSnd_Decoder::ogresf_read(void *ptr, sf_count_t count, void *user_data) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->read(ptr, count); +} + +sf_count_t MpgSnd_Decoder::ogresf_write(const void*, sf_count_t, void*) +{ return -1; } + +sf_count_t MpgSnd_Decoder::ogresf_tell(void *user_data) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->tell(); +} + +// +// libmpg13 io callbacks +// +ssize_t MpgSnd_Decoder::ogrempg_read(void *user_data, void *ptr, size_t count) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + return stream->read(ptr, count); +} + +off_t MpgSnd_Decoder::ogrempg_lseek(void *user_data, off_t offset, int whence) +{ + Ogre::DataStreamPtr stream = static_cast(user_data)->mDataStream; + + if(whence == SEEK_CUR) + stream->seek(stream->tell()+offset); + else if(whence == SEEK_SET) + stream->seek(offset); + else if(whence == SEEK_END) + stream->seek(stream->size()+offset); + else + return -1; + + return stream->tell(); +} + + +void MpgSnd_Decoder::open(const std::string &fname) +{ + close(); + mDataStream = mResourceMgr.openResource(fname); + + SF_VIRTUAL_IO streamIO = { + ogresf_get_filelen, ogresf_seek, + ogresf_read, ogresf_write, ogresf_tell + }; + mSndFile = sf_open_virtual(&streamIO, SFM_READ, &mSndInfo, this); + if(mSndFile) + { + if(mSndInfo.channels == 1) + mChanConfig = ChannelConfig_Mono; + else if(mSndInfo.channels == 2) + mChanConfig = ChannelConfig_Stereo; + else + { + sf_close(mSndFile); + mSndFile = NULL; + fail("Unsupported channel count in "+fname); + } + mSampleRate = mSndInfo.samplerate; + return; + } + mDataStream->seek(0); + + mMpgFile = mpg123_new(NULL, NULL); + if(mMpgFile && mpg123_replace_reader_handle(mMpgFile, ogrempg_read, ogrempg_lseek, NULL) == MPG123_OK && + mpg123_open_handle(mMpgFile, this) == MPG123_OK) + { + try + { + int encoding, channels; + long rate; + if(mpg123_getformat(mMpgFile, &rate, &channels, &encoding) != MPG123_OK) + fail("Failed to get audio format"); + if(encoding != MPG123_ENC_SIGNED_16) + fail("Unsupported encoding in "+fname); + if(channels != 1 && channels != 2) + fail("Unsupported channel count in "+fname); + mChanConfig = ((channels==2)?ChannelConfig_Stereo:ChannelConfig_Mono); + mSampleRate = rate; + return; + } + catch(std::exception &e) + { + mpg123_close(mMpgFile); + mpg123_delete(mMpgFile); + mMpgFile = NULL; + throw; + } + mpg123_close(mMpgFile); + } + if(mMpgFile) + mpg123_delete(mMpgFile); + mMpgFile = NULL; + + fail("Unsupported file type: "+fname); +} + +void MpgSnd_Decoder::close() +{ + if(mSndFile) + sf_close(mSndFile); + mSndFile = NULL; + + if(mMpgFile) + { + mpg123_close(mMpgFile); + mpg123_delete(mMpgFile); + mMpgFile = NULL; + } + + mDataStream.setNull(); +} + +void MpgSnd_Decoder::getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) +{ + if(!mSndFile && !mMpgFile) + fail("No open file"); + + *samplerate = mSampleRate; + *chans = mChanConfig; + *type = SampleType_Int16; +} + +size_t MpgSnd_Decoder::read(char *buffer, size_t bytes) +{ + size_t got = 0; + + if(mSndFile) + { + got = sf_read_short(mSndFile, (short*)buffer, bytes/2)*2; + } + else if(mMpgFile) + { + int err; + err = mpg123_read(mMpgFile, (unsigned char*)buffer, bytes, &got); + if(err != MPG123_OK && err != MPG123_DONE) + fail("Failed to read from file"); + } + return got; +} + +void MpgSnd_Decoder::readAll(std::vector &output) +{ + if(mSndFile && mSndInfo.frames > 0) + { + size_t pos = output.size(); + output.resize(pos + mSndInfo.frames*mSndInfo.channels*2); + sf_readf_short(mSndFile, (short*)(output.data()+pos), mSndInfo.frames); + return; + } + // Fallback in case we don't know the total already + Sound_Decoder::readAll(output); +} + +void MpgSnd_Decoder::rewind() +{ + if(!mSndFile && !mMpgFile) + fail("No open file"); + + if(mSndFile) + { + if(sf_seek(mSndFile, 0, SEEK_SET) == -1) + fail("seek failed"); + } + else if(mMpgFile) + { + if(mpg123_seek(mMpgFile, 0, SEEK_SET) < 0) + fail("seek failed"); + } +} + +MpgSnd_Decoder::MpgSnd_Decoder() : mSndFile(NULL), mMpgFile(NULL) +{ + static bool initdone = false; + if(!initdone) + mpg123_init(); + initdone = true; +} + +MpgSnd_Decoder::~MpgSnd_Decoder() +{ + close(); +} + +} + +#endif diff --git a/apps/openmw/mwsound/mpgsnd_decoder.hpp b/apps/openmw/mwsound/mpgsnd_decoder.hpp new file mode 100644 index 000000000..870773edc --- /dev/null +++ b/apps/openmw/mwsound/mpgsnd_decoder.hpp @@ -0,0 +1,57 @@ +#ifndef GAME_SOUND_MPGSND_DECODER_H +#define GAME_SOUND_MPGSND_DECODER_H + +#include + +#include + +#include "mpg123.h" +#include "sndfile.h" + +#include "sound_decoder.hpp" + + +namespace MWSound +{ + class MpgSnd_Decoder : public Sound_Decoder + { + SF_INFO mSndInfo; + SNDFILE *mSndFile; + mpg123_handle *mMpgFile; + + Ogre::DataStreamPtr mDataStream; + static sf_count_t ogresf_get_filelen(void *user_data); + static sf_count_t ogresf_seek(sf_count_t offset, int whence, void *user_data); + static sf_count_t ogresf_read(void *ptr, sf_count_t count, void *user_data); + static sf_count_t ogresf_write(const void*, sf_count_t, void*); + static sf_count_t ogresf_tell(void *user_data); + static ssize_t ogrempg_read(void*, void*, size_t); + static off_t ogrempg_lseek(void*, off_t, int); + + ChannelConfig mChanConfig; + int mSampleRate; + + virtual void open(const std::string &fname); + virtual void close(); + + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type); + + virtual size_t read(char *buffer, size_t bytes); + virtual void readAll(std::vector &output); + virtual void rewind(); + + MpgSnd_Decoder& operator=(const MpgSnd_Decoder &rhs); + MpgSnd_Decoder(const MpgSnd_Decoder &rhs); + + MpgSnd_Decoder(); + public: + virtual ~MpgSnd_Decoder(); + + friend class SoundManager; + }; +#ifndef DEFAULT_DECODER +#define DEFAULT_DECODER (::MWSound::MpgSnd_Decoder) +#endif +}; + +#endif diff --git a/apps/openmw/mwsound/openal_output.cpp b/apps/openmw/mwsound/openal_output.cpp new file mode 100644 index 000000000..c06947403 --- /dev/null +++ b/apps/openmw/mwsound/openal_output.cpp @@ -0,0 +1,772 @@ +#include +#include +#include +#include + +#include + +#include "openal_output.hpp" +#include "sound_decoder.hpp" +#include "sound.hpp" +#include "soundmanager.hpp" + +#ifndef ALC_ALL_DEVICES_SPECIFIER +#define ALC_ALL_DEVICES_SPECIFIER 0x1013 +#endif + + +namespace MWSound +{ + +static void fail(const std::string &msg) +{ throw std::runtime_error("OpenAL exception: " + msg); } + +static void throwALCerror(ALCdevice *device) +{ + ALCenum err = alcGetError(device); + if(err != ALC_NO_ERROR) + fail(alcGetString(device, err)); +} + +static void throwALerror() +{ + ALenum err = alGetError(); + if(err != AL_NO_ERROR) + fail(alGetString(err)); +} + + +static ALenum getALFormat(ChannelConfig chans, SampleType type) +{ + static const struct { + ALenum format; + ChannelConfig chans; + SampleType type; + } fmtlist[] = { + { AL_FORMAT_MONO16, ChannelConfig_Mono, SampleType_Int16 }, + { AL_FORMAT_MONO8, ChannelConfig_Mono, SampleType_UInt8 }, + { AL_FORMAT_STEREO16, ChannelConfig_Stereo, SampleType_Int16 }, + { AL_FORMAT_STEREO8, ChannelConfig_Stereo, SampleType_UInt8 }, + }; + static const size_t fmtlistsize = sizeof(fmtlist)/sizeof(fmtlist[0]); + + for(size_t i = 0;i < fmtlistsize;i++) + { + if(fmtlist[i].chans == chans && fmtlist[i].type == type) + return fmtlist[i].format; + } + fail(std::string("Unsupported sound format (")+getChannelConfigName(chans)+", "+getSampleTypeName(type)+")"); + return AL_NONE; +} + +// +// A streaming OpenAL sound. +// +class OpenAL_SoundStream : public Sound +{ + static const ALuint sNumBuffers = 6; + static const ALfloat sBufferLength = 0.125f; + + OpenAL_Output &mOutput; + + ALuint mSource; + ALuint mBuffers[sNumBuffers]; + + ALenum mFormat; + ALsizei mSampleRate; + ALuint mBufferSize; + + DecoderPtr mDecoder; + + volatile bool mIsFinished; + + OpenAL_SoundStream(const OpenAL_SoundStream &rhs); + OpenAL_SoundStream& operator=(const OpenAL_SoundStream &rhs); + +public: + OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder); + virtual ~OpenAL_SoundStream(); + + virtual void stop(); + virtual bool isPlaying(); + virtual void update(const float *pos); + + void play(); + bool process(); +}; + +// +// A background streaming thread (keeps active streams processed) +// +struct OpenAL_Output::StreamThread { + typedef std::vector StreamVec; + StreamVec mStreams; + boost::mutex mMutex; + boost::thread mThread; + + StreamThread() + : mThread(boost::ref(*this)) + { + } + ~StreamThread() + { + mThread.interrupt(); + } + + // boost::thread entry point + void operator()() + { + while(1) + { + mMutex.lock(); + StreamVec::iterator iter = mStreams.begin(); + while(iter != mStreams.end()) + { + if((*iter)->process() == false) + iter = mStreams.erase(iter); + else + iter++; + } + mMutex.unlock(); + boost::this_thread::sleep(boost::posix_time::milliseconds(50)); + } + } + + void add(OpenAL_SoundStream *stream) + { + mMutex.lock(); + if(std::find(mStreams.begin(), mStreams.end(), stream) == mStreams.end()) + mStreams.push_back(stream); + mMutex.unlock(); + } + + void remove(OpenAL_SoundStream *stream) + { + mMutex.lock(); + StreamVec::iterator iter = std::find(mStreams.begin(), mStreams.end(), stream); + if(iter != mStreams.end()) + mStreams.erase(iter); + mMutex.unlock(); + } + + void removeAll() + { + mMutex.lock(); + mStreams.clear(); + mMutex.unlock(); + } + +private: + StreamThread(const StreamThread &rhs); + StreamThread& operator=(const StreamThread &rhs); +}; + + +OpenAL_SoundStream::OpenAL_SoundStream(OpenAL_Output &output, ALuint src, DecoderPtr decoder) + : mOutput(output), mSource(src), mDecoder(decoder), mIsFinished(true) +{ + throwALerror(); + + alGenBuffers(sNumBuffers, mBuffers); + throwALerror(); + try + { + int srate; + ChannelConfig chans; + SampleType type; + + mDecoder->getInfo(&srate, &chans, &type); + mFormat = getALFormat(chans, type); + mSampleRate = srate; + + mBufferSize = static_cast(sBufferLength*srate); + mBufferSize = framesToBytes(mBufferSize, chans, type); + } + catch(std::exception &e) + { + mOutput.mFreeSources.push_back(mSource); + alDeleteBuffers(sNumBuffers, mBuffers); + alGetError(); + throw; + } +} +OpenAL_SoundStream::~OpenAL_SoundStream() +{ + mOutput.mStreamThread->remove(this); + + alSourceStop(mSource); + alSourcei(mSource, AL_BUFFER, 0); + + mOutput.mFreeSources.push_back(mSource); + alDeleteBuffers(sNumBuffers, mBuffers); + alGetError(); + + mDecoder->close(); +} + +void OpenAL_SoundStream::play() +{ + std::vector data(mBufferSize); + + alSourceStop(mSource); + alSourcei(mSource, AL_BUFFER, 0); + throwALerror(); + + for(ALuint i = 0;i < sNumBuffers;i++) + { + size_t got; + got = mDecoder->read(data.data(), data.size()); + alBufferData(mBuffers[i], mFormat, data.data(), got, mSampleRate); + } + throwALerror(); + + alSourceQueueBuffers(mSource, sNumBuffers, mBuffers); + alSourcePlay(mSource); + throwALerror(); + + mIsFinished = false; + mOutput.mStreamThread->add(this); +} + +void OpenAL_SoundStream::stop() +{ + mOutput.mStreamThread->remove(this); + mIsFinished = true; + + alSourceStop(mSource); + alSourcei(mSource, AL_BUFFER, 0); + throwALerror(); + + mDecoder->rewind(); +} + +bool OpenAL_SoundStream::isPlaying() +{ + ALint state; + + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + throwALerror(); + + if(state == AL_PLAYING) + return true; + return !mIsFinished; +} + +void OpenAL_SoundStream::update(const float *pos) +{ + alSource3f(mSource, AL_POSITION, pos[0], pos[2], -pos[1]); + alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + throwALerror(); +} + +bool OpenAL_SoundStream::process() +{ + bool finished = mIsFinished; + ALint processed, state; + + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + alGetSourcei(mSource, AL_BUFFERS_PROCESSED, &processed); + throwALerror(); + + if(processed > 0) + { + std::vector data(mBufferSize); + do { + ALuint bufid; + size_t got; + + alSourceUnqueueBuffers(mSource, 1, &bufid); + processed--; + + if(finished) + continue; + + got = mDecoder->read(data.data(), data.size()); + finished = (got < data.size()); + if(got > 0) + { + alBufferData(bufid, mFormat, data.data(), got, mSampleRate); + alSourceQueueBuffers(mSource, 1, &bufid); + } + } while(processed > 0); + throwALerror(); + } + + if(state != AL_PLAYING && state != AL_PAUSED) + { + ALint queued; + + alGetSourcei(mSource, AL_BUFFERS_QUEUED, &queued); + throwALerror(); + if(queued > 0) + { + alSourcePlay(mSource); + throwALerror(); + } + } + + mIsFinished = finished; + return !finished; +} + +// +// A regular OpenAL sound +// +class OpenAL_Sound : public Sound +{ + OpenAL_Output &mOutput; + + ALuint mSource; + ALuint mBuffer; + + OpenAL_Sound(const OpenAL_Sound &rhs); + OpenAL_Sound& operator=(const OpenAL_Sound &rhs); + +public: + OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf); + virtual ~OpenAL_Sound(); + + virtual void stop(); + virtual bool isPlaying(); + virtual void update(const float *pos); +}; + +OpenAL_Sound::OpenAL_Sound(OpenAL_Output &output, ALuint src, ALuint buf) + : mOutput(output), mSource(src), mBuffer(buf) +{ +} +OpenAL_Sound::~OpenAL_Sound() +{ + alSourceStop(mSource); + alSourcei(mSource, AL_BUFFER, 0); + + mOutput.mFreeSources.push_back(mSource); + mOutput.bufferFinished(mBuffer); +} + +void OpenAL_Sound::stop() +{ + alSourceStop(mSource); + throwALerror(); +} + +bool OpenAL_Sound::isPlaying() +{ + ALint state; + + alGetSourcei(mSource, AL_SOURCE_STATE, &state); + throwALerror(); + + return state==AL_PLAYING; +} + +void OpenAL_Sound::update(const float *pos) +{ + alSource3f(mSource, AL_POSITION, pos[0], pos[2], -pos[1]); + alSource3f(mSource, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(mSource, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + throwALerror(); +} + + +// +// An OpenAL output device +// +std::vector OpenAL_Output::enumerate() +{ + std::vector devlist; + const ALCchar *devnames; + + if(alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) + devnames = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER); + else + devnames = alcGetString(NULL, ALC_DEVICE_SPECIFIER); + while(devnames && *devnames) + { + devlist.push_back(devnames); + devnames += strlen(devnames)+1; + } + return devlist; +} + +void OpenAL_Output::init(const std::string &devname) +{ + if(mDevice || mContext) + fail("Device already open"); + + mDevice = alcOpenDevice(devname.c_str()); + if(!mDevice) + { + if(devname.empty()) + fail("Failed to open default device"); + else + fail("Failed to open \""+devname+"\""); + } + if(alcIsExtensionPresent(mDevice, "ALC_ENUMERATE_ALL_EXT")) + std::cout << "Opened \""<removeAll(); + + if(!mFreeSources.empty()) + { + alDeleteSources(mFreeSources.size(), mFreeSources.data()); + mFreeSources.clear(); + } + + mBufferRefs.clear(); + mUnusedBuffers.clear(); + while(!mBufferCache.empty()) + { + alDeleteBuffers(1, &mBufferCache.begin()->second); + mBufferCache.erase(mBufferCache.begin()); + } + + alcMakeContextCurrent(0); + if(mContext) + alcDestroyContext(mContext); + mContext = 0; + if(mDevice) + alcCloseDevice(mDevice); + mDevice = 0; +} + + +ALuint OpenAL_Output::getBuffer(const std::string &fname) +{ + ALuint buf = 0; + + NameMap::iterator iditer = mBufferCache.find(fname); + if(iditer != mBufferCache.end()) + { + buf = iditer->second; + if(mBufferRefs[buf]++ == 0) + { + IDDq::iterator iter = std::find(mUnusedBuffers.begin(), + mUnusedBuffers.end(), buf); + if(iter != mUnusedBuffers.end()) + mUnusedBuffers.erase(iter); + } + + return buf; + } + throwALerror(); + + std::vector data; + ChannelConfig chans; + SampleType type; + ALenum format; + int srate; + + DecoderPtr decoder = mManager.getDecoder(); + try + { + decoder->open(fname); + } + catch(Ogre::FileNotFoundException &e) + { + std::string::size_type pos = fname.rfind('.'); + if(pos == std::string::npos) + throw; + decoder->open(fname.substr(0, pos)+".mp3"); + } + + decoder->getInfo(&srate, &chans, &type); + format = getALFormat(chans, type); + + decoder->readAll(data); + decoder->close(); + + alGenBuffers(1, &buf); + throwALerror(); + + alBufferData(buf, format, data.data(), data.size(), srate); + mBufferCache[fname] = buf; + mBufferRefs[buf] = 1; + + ALint bufsize = 0; + alGetBufferi(buf, AL_SIZE, &bufsize); + mBufferCacheMemSize += bufsize; + + // NOTE: Max buffer cache: 15MB + while(mBufferCacheMemSize > 15*1024*1024) + { + if(mUnusedBuffers.empty()) + { + std::cout <<"No more unused buffers to clear!"<< std::endl; + break; + } + + ALuint oldbuf = mUnusedBuffers.front(); + mUnusedBuffers.pop_front(); + + NameMap::iterator nameiter = mBufferCache.begin(); + while(nameiter != mBufferCache.end()) + { + if(nameiter->second == oldbuf) + mBufferCache.erase(nameiter++); + else + nameiter++; + } + + bufsize = 0; + alGetBufferi(oldbuf, AL_SIZE, &bufsize); + alDeleteBuffers(1, &oldbuf); + mBufferCacheMemSize -= bufsize; + } + return buf; +} + +void OpenAL_Output::bufferFinished(ALuint buf) +{ + if(mBufferRefs.at(buf)-- == 1) + { + mBufferRefs.erase(mBufferRefs.find(buf)); + mUnusedBuffers.push_back(buf); + } +} + + +Sound* OpenAL_Output::playSound(const std::string &fname, float volume, float pitch, bool loop) +{ + throwALerror(); + + std::auto_ptr sound; + ALuint src=0, buf=0; + + if(mFreeSources.empty()) + fail("No free sources"); + src = mFreeSources.back(); + mFreeSources.pop_back(); + + try + { + buf = getBuffer(fname); + sound.reset(new OpenAL_Sound(*this, src, buf)); + } + catch(std::exception &e) + { + mFreeSources.push_back(src); + if(buf && alIsBuffer(buf)) + bufferFinished(buf); + alGetError(); + throw; + } + + alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(src, AL_MAX_DISTANCE, 1000.0f); + alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); + + alSourcef(src, AL_GAIN, volume); + alSourcef(src, AL_PITCH, pitch); + + alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(src, AL_LOOPING, (loop?AL_TRUE:AL_FALSE)); + throwALerror(); + + alSourcei(src, AL_BUFFER, buf); + alSourcePlay(src); + throwALerror(); + + return sound.release(); +} + +Sound* OpenAL_Output::playSound3D(const std::string &fname, const float *pos, float volume, float pitch, + float min, float max, bool loop) +{ + throwALerror(); + + std::auto_ptr sound; + ALuint src=0, buf=0; + + if(mFreeSources.empty()) + fail("No free sources"); + src = mFreeSources.back(); + mFreeSources.pop_back(); + + try + { + buf = getBuffer(fname); + sound.reset(new OpenAL_Sound(*this, src, buf)); + } + catch(std::exception &e) + { + mFreeSources.push_back(src); + if(buf && alIsBuffer(buf)) + bufferFinished(buf); + alGetError(); + throw; + } + + alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]); + alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(src, AL_REFERENCE_DISTANCE, min); + alSourcef(src, AL_MAX_DISTANCE, max); + alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f); + + alSourcef(src, AL_GAIN, volume); + alSourcef(src, AL_PITCH, pitch); + + alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(src, AL_LOOPING, (loop?AL_TRUE:AL_FALSE)); + throwALerror(); + + alSourcei(src, AL_BUFFER, buf); + alSourcePlay(src); + throwALerror(); + + return sound.release(); +} + + +Sound* OpenAL_Output::streamSound(const std::string &fname, float volume, float pitch) +{ + throwALerror(); + + std::auto_ptr sound; + ALuint src; + + if(mFreeSources.empty()) + fail("No free sources"); + src = mFreeSources.back(); + mFreeSources.pop_back(); + + try + { + DecoderPtr decoder = mManager.getDecoder(); + decoder->open(fname); + sound.reset(new OpenAL_SoundStream(*this, src, decoder)); + } + catch(std::exception &e) + { + mFreeSources.push_back(src); + throw; + } + + alSource3f(src, AL_POSITION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(src, AL_REFERENCE_DISTANCE, 1.0f); + alSourcef(src, AL_MAX_DISTANCE, 1000.0f); + alSourcef(src, AL_ROLLOFF_FACTOR, 0.0f); + + alSourcef(src, AL_GAIN, volume); + alSourcef(src, AL_PITCH, pitch); + + alSourcei(src, AL_SOURCE_RELATIVE, AL_TRUE); + alSourcei(src, AL_LOOPING, AL_FALSE); + throwALerror(); + + sound->play(); + return sound.release(); +} + +Sound* OpenAL_Output::streamSound3D(const std::string &fname, const float *pos, float volume, float pitch, + float min, float max) +{ + throwALerror(); + + std::auto_ptr sound; + ALuint src; + + if(mFreeSources.empty()) + fail("No free sources"); + src = mFreeSources.back(); + mFreeSources.pop_back(); + + try + { + DecoderPtr decoder = mManager.getDecoder(); + decoder->open(fname); + sound.reset(new OpenAL_SoundStream(*this, src, decoder)); + } + catch(std::exception &e) + { + mFreeSources.push_back(src); + throw; + } + + alSource3f(src, AL_POSITION, pos[0], pos[2], -pos[1]); + alSource3f(src, AL_DIRECTION, 0.0f, 0.0f, 0.0f); + alSource3f(src, AL_VELOCITY, 0.0f, 0.0f, 0.0f); + + alSourcef(src, AL_REFERENCE_DISTANCE, min); + alSourcef(src, AL_MAX_DISTANCE, max); + alSourcef(src, AL_ROLLOFF_FACTOR, 1.0f); + + alSourcef(src, AL_GAIN, volume); + alSourcef(src, AL_PITCH, pitch); + + alSourcei(src, AL_SOURCE_RELATIVE, AL_FALSE); + alSourcei(src, AL_LOOPING, AL_FALSE); + throwALerror(); + + sound->play(); + return sound.release(); +} + + +void OpenAL_Output::updateListener(const float *pos, const float *atdir, const float *updir) +{ + float orient[6] = { + atdir[0], atdir[2], -atdir[1], + updir[0], updir[2], -updir[1] + }; + + alListener3f(AL_POSITION, pos[0], pos[2], -pos[1]); + alListenerfv(AL_ORIENTATION, orient); + throwALerror(); +} + + +OpenAL_Output::OpenAL_Output(SoundManager &mgr) + : Sound_Output(mgr), mDevice(0), mContext(0), mBufferCacheMemSize(0), + mStreamThread(new StreamThread) +{ +} + +OpenAL_Output::~OpenAL_Output() +{ + deinit(); +} + +} diff --git a/apps/openmw/mwsound/openal_output.hpp b/apps/openmw/mwsound/openal_output.hpp new file mode 100644 index 000000000..e8154e906 --- /dev/null +++ b/apps/openmw/mwsound/openal_output.hpp @@ -0,0 +1,73 @@ +#ifndef GAME_SOUND_OPENAL_OUTPUT_H +#define GAME_SOUND_OPENAL_OUTPUT_H + +#include +#include +#include +#include + +#include "alc.h" +#include "al.h" + +#include "sound_output.hpp" + +namespace MWSound +{ + class SoundManager; + class Sound; + + class OpenAL_Output : public Sound_Output + { + ALCdevice *mDevice; + ALCcontext *mContext; + + typedef std::vector IDVec; + IDVec mFreeSources; + + typedef std::map NameMap; + NameMap mBufferCache; + + typedef std::map IDRefMap; + IDRefMap mBufferRefs; + + typedef std::deque IDDq; + IDDq mUnusedBuffers; + + uint64_t mBufferCacheMemSize; + + ALuint getBuffer(const std::string &fname); + void bufferFinished(ALuint buffer); + + virtual std::vector enumerate(); + virtual void init(const std::string &devname=""); + virtual void deinit(); + + virtual Sound *playSound(const std::string &fname, float volume, float pitch, bool loop); + virtual Sound *playSound3D(const std::string &fname, const float *pos, float volume, float pitch, + float min, float max, bool loop); + + virtual Sound *streamSound(const std::string &fname, float volume, float pitch); + virtual Sound *streamSound3D(const std::string &fname, const float *pos, float volume, float pitch, + float min, float max); + + virtual void updateListener(const float *pos, const float *atdir, const float *updir); + + OpenAL_Output& operator=(const OpenAL_Output &rhs); + OpenAL_Output(const OpenAL_Output &rhs); + + OpenAL_Output(SoundManager &mgr); + virtual ~OpenAL_Output(); + + class StreamThread; + std::auto_ptr mStreamThread; + + friend class OpenAL_Sound; + friend class OpenAL_SoundStream; + friend class SoundManager; + }; +#ifndef DEFAULT_OUTPUT +#define DEFAULT_OUTPUT (::MWSound::OpenAL_Output) +#endif +}; + +#endif diff --git a/apps/openmw/mwsound/sound.hpp b/apps/openmw/mwsound/sound.hpp new file mode 100644 index 000000000..f9e7ab427 --- /dev/null +++ b/apps/openmw/mwsound/sound.hpp @@ -0,0 +1,24 @@ +#ifndef GAME_SOUND_SOUND_H +#define GAME_SOUND_SOUND_H + +namespace MWSound +{ + class Sound + { + virtual void stop() = 0; + virtual bool isPlaying() = 0; + virtual void update(const float *pos) = 0; + + Sound& operator=(const Sound &rhs); + Sound(const Sound &rhs); + + public: + Sound() { } + virtual ~Sound() { } + + friend class OpenAL_Output; + friend class SoundManager; + }; +} + +#endif diff --git a/apps/openmw/mwsound/sound_decoder.hpp b/apps/openmw/mwsound/sound_decoder.hpp new file mode 100644 index 000000000..9c28d5ff5 --- /dev/null +++ b/apps/openmw/mwsound/sound_decoder.hpp @@ -0,0 +1,48 @@ +#ifndef GAME_SOUND_SOUND_DECODER_H +#define GAME_SOUND_SOUND_DECODER_H + +#include + +#include + +namespace MWSound +{ + enum SampleType { + SampleType_UInt8, + SampleType_Int16 + }; + const char *getSampleTypeName(SampleType type); + + enum ChannelConfig { + ChannelConfig_Mono, + ChannelConfig_Stereo + }; + const char *getChannelConfigName(ChannelConfig config); + + size_t framesToBytes(size_t frames, ChannelConfig config, SampleType type); + size_t bytesToFrames(size_t bytes, ChannelConfig config, SampleType type); + + struct Sound_Decoder + { + Ogre::ResourceGroupManager &mResourceMgr; + + virtual void open(const std::string &fname) = 0; + virtual void close() = 0; + + virtual void getInfo(int *samplerate, ChannelConfig *chans, SampleType *type) = 0; + + virtual size_t read(char *buffer, size_t bytes) = 0; + virtual void readAll(std::vector &output); + virtual void rewind() = 0; + + Sound_Decoder() : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) + { } + virtual ~Sound_Decoder() { } + + private: + Sound_Decoder(const Sound_Decoder &rhs); + Sound_Decoder& operator=(const Sound_Decoder &rhs); + }; +} + +#endif diff --git a/apps/openmw/mwsound/sound_output.hpp b/apps/openmw/mwsound/sound_output.hpp new file mode 100644 index 000000000..1722165e4 --- /dev/null +++ b/apps/openmw/mwsound/sound_output.hpp @@ -0,0 +1,44 @@ +#ifndef GAME_SOUND_SOUND_OUTPUT_H +#define GAME_SOUND_SOUND_OUTPUT_H + +#include +#include + +#include "../mwworld/ptr.hpp" + +namespace MWSound +{ + class SoundManager; + class Sound_Decoder; + class Sound; + + class Sound_Output + { + SoundManager &mManager; + + virtual std::vector enumerate() = 0; + virtual void init(const std::string &devname="") = 0; + virtual void deinit() = 0; + + virtual Sound *playSound(const std::string &fname, float volume, float pitch, bool loop) = 0; + virtual Sound *playSound3D(const std::string &fname, const float *pos, float volume, float pitch, + float min, float max, bool loop) = 0; + virtual Sound *streamSound(const std::string &fname, float volume, float pitch) = 0; + virtual Sound *streamSound3D(const std::string &fname, const float *pos, float volume, float pitch, + float min, float max) = 0; + + virtual void updateListener(const float *pos, const float *atdir, const float *updir) = 0; + + Sound_Output& operator=(const Sound_Output &rhs); + Sound_Output(const Sound_Output &rhs); + + Sound_Output(SoundManager &mgr) : mManager(mgr) { } + public: + virtual ~Sound_Output() { } + + friend class OpenAL_Output; + friend class SoundManager; + }; +} + +#endif diff --git a/apps/openmw/mwsound/soundmanager.cpp b/apps/openmw/mwsound/soundmanager.cpp index 226796603..f626ec158 100644 --- a/apps/openmw/mwsound/soundmanager.cpp +++ b/apps/openmw/mwsound/soundmanager.cpp @@ -6,111 +6,79 @@ #include -#include -#include -#include - #include #include "../mwworld/environment.hpp" #include "../mwworld/world.hpp" #include "../mwworld/player.hpp" -/* Set up the sound manager to use Audiere, FFMPEG or - MPG123/libsndfile for input. The OPENMW_USE_x macros are set in - CMakeLists.txt. -*/ -#ifdef OPENMW_USE_AUDIERE -#include -#define SOUND_FACTORY OpenAL_Audiere_Factory -#define SOUND_OUT "OpenAL" -#define SOUND_IN "Audiere" -#endif +#include "sound_output.hpp" +#include "sound_decoder.hpp" +#include "sound.hpp" -#ifdef OPENMW_USE_FFMPEG -#include -#define SOUND_FACTORY OpenAL_FFMpeg_Factory +#include "openal_output.hpp" #define SOUND_OUT "OpenAL" +/* Set up the sound manager to use FFMPEG or MPG123+libsndfile for input. The + * OPENMW_USE_x macros are set in CMakeLists.txt. +*/ +#ifdef OPENMW_USE_FFMPEG +#include "ffmpeg_decoder.hpp" +#ifndef SOUND_IN #define SOUND_IN "FFmpeg" #endif +#endif #ifdef OPENMW_USE_MPG123 -#include -#define SOUND_FACTORY OpenAL_SndFile_Mpg123_Factory -#define SOUND_OUT "OpenAL" +#include "mpgsnd_decoder.hpp" +#ifndef SOUND_IN #define SOUND_IN "mpg123,sndfile" #endif +#endif -using namespace Mangle::Sound; -typedef OEngine::Sound::SoundManager OEManager; - -// Set the position on a sound based on a Ptr. -static void setPos(SoundPtr &snd, const MWWorld::Ptr ref) -{ - // Get sound position from the reference - const float *pos = ref.getCellRef().pos.pos; - - // Move the sound, converting from MW coordinates to Ogre - // coordinates. - snd->setPos(pos[0], pos[2], -pos[1]); -} namespace MWSound { - - SoundManager::SoundManager(Ogre::Root *root, Ogre::Camera *camera, - const Files::PathContainer& dataDirs, - bool useSound, bool fsstrict, MWWorld::Environment& environment) - : mFSStrict(fsstrict) + SoundManager::SoundManager(bool useSound, MWWorld::Environment& environment) + : mResourceMgr(Ogre::ResourceGroupManager::getSingleton()) , mEnvironment(environment) - , mgr(new OEManager(SoundFactoryPtr(new SOUND_FACTORY))) - , updater(mgr) - , cameraTracker(mgr) - , mCurrentPlaylist(NULL) - , mUsingSound(useSound) { - if(useSound) - { - // The music library will accept these filetypes - // If none is given then it will accept all filetypes - std::vector acceptableExtensions; - acceptableExtensions.push_back(".mp3"); - acceptableExtensions.push_back(".wav"); - acceptableExtensions.push_back(".ogg"); - acceptableExtensions.push_back(".flac"); - - // Makes a list of all sound files, searches in reverse for priority reasons - for (Files::PathContainer::const_reverse_iterator it = dataDirs.rbegin(); it != dataDirs.rend(); ++it) - { - Files::FileLister(*it / std::string("Sound"), mSoundFiles, true); - } + if(!useSound) + return; - // Makes a FileLibrary of all music files, searches in reverse for priority reasons - for (Files::PathContainer::const_reverse_iterator it = dataDirs.rbegin(); it != dataDirs.rend(); ++it) - { - mMusicLibrary.add(*it / std::string("Music"), true, mFSStrict, acceptableExtensions); - } + std::cout << "Sound output: " << SOUND_OUT << std::endl; + std::cout << "Sound decoder: " << SOUND_IN << std::endl; - std::string anything = "anything"; // anything is better that a segfault - mCurrentPlaylist = mMusicLibrary.section(anything, mFSStrict); // now points to an empty path + try + { + mOutput.reset(new DEFAULT_OUTPUT(*this)); - std::cout << "Sound output: " << SOUND_OUT << std::endl; - std::cout << "Sound decoder: " << SOUND_IN << std::endl; - // Attach the camera to the camera tracker - cameraTracker.followCamera(camera); + std::vector names = mOutput->enumerate(); + std::cout <<"Enumerated output devices:"<< std::endl; + for(size_t i = 0;i < names.size();i++) + std::cout <<" "<addFrameListener(&updater); + mOutput->init(); + } + catch(std::exception &e) + { + std::cout <<"Sound init failed: "<getStore().sounds.search(soundId); - if(snd == NULL) return ""; - - if(snd->data.volume == 0) - volume = 0.0f; - else - volume *= pow(10.0, (snd->data.volume/255.0f*3348.0 - 3348.0) / 2000.0); - - if(snd->data.minRange == 0 && snd->data.maxRange == 0) - { - min = 100.0f; - max = 2000.0f; - } - else - { - min = snd->data.minRange * 20.0f; - max = snd->data.maxRange * 50.0f; - min = std::max(min, 1.0f); - max = std::max(min, max); - } - - return Files::FileListLocator(mSoundFiles, snd->sound, mFSStrict, false); - } + const ESM::Sound *snd = mEnvironment.mWorld->getStore().sounds.search(soundId); + if(snd == NULL) + throw std::runtime_error(std::string("Failed to lookup sound ")+soundId); - // Add a sound to the list and play it - void SoundManager::add(const std::string &file, - MWWorld::Ptr ptr, - const std::string &id, - float volume, float pitch, - float min, float max, - bool loop, bool untracked) - { - try + if(snd->data.volume == 0) + volume = 0.0f; + else + volume *= pow(10.0, (snd->data.volume/255.0f*3348.0 - 3348.0) / 2000.0); + + if(snd->data.minRange == 0 && snd->data.maxRange == 0) { - SoundPtr snd = mgr->load(file); - snd->setRepeat(loop); - snd->setVolume(volume); - snd->setPitch(pitch); - snd->setRange(min,max); - setPos(snd, ptr); - snd->play(); - - if (!untracked) - { - sounds[ptr][id] = WSoundPtr(snd); - } + min = 100.0f; + max = 2000.0f; } - catch(...) + else { - std::cout << "Error loading " << file << ", skipping.\n"; + min = snd->data.minRange * 20.0f; + max = snd->data.maxRange * 50.0f; + min = std::max(min, 1.0f); + max = std::max(min, max); } + + return std::string("Sound/")+snd->sound; } - // Clears all the sub-elements of a given iterator, and then - // removes it from 'sounds'. - void SoundManager::clearAll(PtrMap::iterator& it) + + bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const { - IDMap::iterator sit = it->second.begin(); + SoundMap::const_iterator snditer = mActiveSounds.find(ptr); + if(snditer == mActiveSounds.end()) + return false; - while(sit != it->second.end()) - { - // Get sound pointer, if any - SoundPtr snd = sit->second.lock(); + IDMap::const_iterator iditer = snditer->second.find(id); + if(iditer == snditer->second.end()) + return false; - // Stop the sound - if(snd) snd->stop(); + return true; + } - sit++; - } - // Remove the ptr reference - sounds.erase(it); + void SoundManager::stopMusic() + { + if(mMusic) + mMusic->stop(); + mMusic.reset(); } - // Stop a sound and remove it from the list. If id="" then - // remove the entire object and stop all its sounds. - void SoundManager::remove(MWWorld::Ptr ptr, const std::string &id) + void SoundManager::streamMusicFull(const std::string& filename) { - PtrMap::iterator it = sounds.find(ptr); - if(it != sounds.end()) + std::cout <<"Playing "<second.find(id); - if(it2 != it->second.end()) - { - // Stop the sound and remove it from the list - SoundPtr snd = it2->second.lock(); - if(snd) snd->stop(); - it->second.erase(it2); - } - } + if(mMusic) + mMusic->stop(); + mMusic.reset(mOutput->streamSound(filename, 0.4f, 1.0f)); } - } - - bool SoundManager::isPlaying(MWWorld::Ptr ptr, const std::string &id) const - { - PtrMap::const_iterator it = sounds.find(ptr); - if(it != sounds.end()) + catch(std::exception &e) { - IDMap::const_iterator it2 = it->second.find(id); - if(it2 != it->second.end()) - { - // Get a shared_ptr from the weak_ptr - SoundPtr snd = it2->second.lock();; - - // Is it still alive? - if(snd) - { - // Then return its status! - return snd->isPlaying(); - } - } + std::cout << "Music Error: " << e.what() << "\n"; } - // Nothing found, sound is not playing - return false; } - // Remove all references to objects belonging to a given cell - void SoundManager::removeCell(const MWWorld::Ptr::CellStore *cell) + void SoundManager::streamMusic(const std::string& filename) { - PtrMap::iterator it2, it = sounds.begin(); - while(it != sounds.end()) - { - // Make sure to increase the iterator before we erase it. - it2 = it++; - if(it2->first.getCell() == cell) - clearAll(it2); - } + streamMusicFull("Music/"+filename); } - void SoundManager::updatePositions(MWWorld::Ptr ptr) + void SoundManager::startRandomTitle() { - // Find the reference (if any) - PtrMap::iterator it = sounds.find(ptr); - if(it != sounds.end()) - { - // Then find all sounds in it (if any) - IDMap::iterator it2 = it->second.begin(); - for(;it2 != it->second.end(); it2++) - { - // Get the sound (if it still exists) - SoundPtr snd = it2->second.lock(); - if(snd) - // Update position - setPos(snd, ptr); - } - } + Ogre::StringVectorPtr filelist; + filelist = mResourceMgr.findResourceNames(Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + "Music/"+mCurrentPlaylist+"/*"); + if(!filelist->size()) + return; + + int i = rand()%filelist->size(); + streamMusicFull((*filelist)[i]); } - void SoundManager::stopMusic() + bool SoundManager::isMusicPlaying() { - if (music) - music->stop(); - setPlaylist(); + return mMusic && mMusic->isPlaying(); } + void SoundManager::playPlaylist(const std::string &playlist) + { + mCurrentPlaylist = playlist; + startRandomTitle(); + } - void SoundManager::streamMusicFull(const std::string& filename) - { - // Play the sound and tell it to stream, if possible. TODO: - // Store the reference, the jukebox will need to check status, - // control volume etc. - if (music) - music->stop(); - music = mgr->load(filename); - music->setStreaming(true); - music->setVolume(0.4); - music->play(); - - } - - void SoundManager::streamMusic(const std::string& filename) + void SoundManager::say(MWWorld::Ptr ptr, const std::string& filename) { - std::string filePath = mMusicLibrary.locate(filename, mFSStrict, true).string(); - if(!filePath.empty()) + try + { + // The range values are not tested + const ESM::Position &pos = ptr.getCellRef().pos; + std::string filePath = std::string("Sound/")+filename; + + SoundPtr sound(mOutput->playSound3D(filePath, pos.pos, 1.0f, 1.0f, 100.0f, 20000.0f, false)); + mActiveSounds[ptr]["_say_sound"] = sound; + } + catch(std::exception &e) { - streamMusicFull(filePath); + std::cout <<"Sound Error: "<empty()) + bool SoundManager::sayDone(MWWorld::Ptr ptr) const { - Files::PathContainer::const_iterator fileIter = mCurrentPlaylist->begin(); - srand( time(NULL) ); - int r = rand() % mCurrentPlaylist->size() + 1; //old random code + return !isPlaying(ptr, "_say_sound"); + } - std::advance(fileIter, r - 1); - std::string music = fileIter->string(); - std::cout << "Playing " << music << "\n"; + void SoundManager::playSound(const std::string& soundId, float volume, float pitch, bool loop) + { + float min, max; try { - streamMusicFull(music); + std::string file = lookup(soundId, volume, min, max); + Sound *sound = mOutput->playSound(file, volume, pitch, loop); + mLooseSounds[soundId] = SoundPtr(sound); } - catch (std::exception &e) + catch(std::exception &e) { - std::cout << " Music Error: " << e.what() << "\n"; + std::cout <<"Sound Error: "<isPlaying(); - } - return test; - } + // Look up the sound in the ESM data + const ESM::Position &pos = ptr.getCellRef().pos; + std::string file = lookup(soundId, volume, min, max); - bool SoundManager::setPlaylist(std::string playlist) - { - const Files::PathContainer* previousPlaylist; - previousPlaylist = mCurrentPlaylist; - if (playlist == "") - { - mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict); + SoundPtr sound(mOutput->playSound3D(file, pos.pos, volume, pitch, min, max, loop)); + if(untracked) mLooseSounds[soundId] = sound; + else mActiveSounds[ptr][soundId] = sound; } - else if(mMusicLibrary.containsSection(playlist, mFSStrict)) - { - mCurrentPlaylist = mMusicLibrary.section(playlist, mFSStrict); - } - else + catch(std::exception &e) { - std::cout << "Warning: playlist named " << playlist << " does not exist.\n"; + std::cout <<"Sound Error: "<second.find(soundId); + if(iditer != snditer->second.end()) { - startRandomTitle(); + iditer->second->stop(); + snditer->second.erase(iditer); + if(snditer->second.empty()) + mActiveSounds.erase(snditer); } - return; - } - - if(!setPlaylist(playlist)) - { - startRandomTitle(); } - else if (!isMusicPlaying()) + else { - startRandomTitle(); + IDMap::iterator iditer = snditer->second.begin(); + while(iditer != snditer->second.end()) + { + iditer->second->stop(); + iditer++; + } + mActiveSounds.erase(snditer); } } - void SoundManager::say (MWWorld::Ptr ptr, const std::string& filename) - { - if (!mUsingSound) - return; - - // The range values are not tested - std::string filePath = Files::FileListLocator(mSoundFiles, filename, mFSStrict, true); - if(!filePath.empty()) - add(filePath, ptr, "_say_sound", 1, 1, 100, 20000, false); - else - std::cout << "Sound file " << filename << " not found, skipping.\n"; - } - - bool SoundManager::sayDone (MWWorld::Ptr ptr) const - { - return !isPlaying(ptr, "_say_sound"); - } - - - void SoundManager::playSound(const std::string& soundId, float volume, float pitch, bool loop) - { - float min, max; - const std::string &file = lookup(soundId, volume, min, max); - if (file != "") + void SoundManager::stopSound(MWWorld::Ptr::CellStore *cell) { - SoundPtr snd = mgr->load(file); - snd->setRepeat(loop); - snd->setVolume(volume); - snd->setRange(min,max); - snd->setPitch(pitch); - snd->setRelative(true); - snd->play(); - - if (loop) + // Remove all references to objects belonging to a given cell + SoundMap::iterator snditer = mActiveSounds.begin(); + while(snditer != mActiveSounds.end()) { - // Only add the looping sound once - IDMap::iterator it = mLoopedSounds.find(soundId); - if(it == mLoopedSounds.end()) + if(snditer->first.getCell() == cell) { - mLoopedSounds[soundId] = WSoundPtr(snd); + IDMap::iterator iditer = snditer->second.begin(); + while(iditer != snditer->second.end()) + { + iditer->second->stop(); + iditer++; + } + mActiveSounds.erase(snditer++); } + else + snditer++; } } - } - - void SoundManager::playSound3D (MWWorld::Ptr ptr, const std::string& soundId, - float volume, float pitch, bool loop, bool untracked) - { - // Look up the sound in the ESM data - float min, max; - const std::string &file = lookup(soundId, volume, min, max); - if (file != "") - add(file, ptr, soundId, volume, pitch, min, max, loop, untracked); - } - - void SoundManager::stopSound3D (MWWorld::Ptr ptr, const std::string& soundId) - { - remove(ptr, soundId); - } - - void SoundManager::stopSound (MWWorld::Ptr::CellStore *cell) - { - removeCell(cell); - } void SoundManager::stopSound(const std::string& soundId) { - IDMap::iterator it = mLoopedSounds.find(soundId); - if(it != mLoopedSounds.end()) + IDMap::iterator iditer = mLooseSounds.find(soundId); + if(iditer != mLooseSounds.end()) { - SoundPtr snd = it->second.lock(); - if(snd) snd->stop(); - mLoopedSounds.erase(it); + iditer->second->stop(); + mLooseSounds.erase(iditer); } } - bool SoundManager::getSoundPlaying (MWWorld::Ptr ptr, const std::string& soundId) const - { - // Mark all sounds as playing, otherwise the scripts will just - // keep trying to play them every frame. + bool SoundManager::getSoundPlaying(MWWorld::Ptr ptr, const std::string& soundId) const + { + return isPlaying(ptr, soundId); + } - return isPlaying(ptr, soundId); - } + void SoundManager::updateObject(MWWorld::Ptr ptr) + { + SoundMap::iterator snditer = mActiveSounds.find(ptr); + if(snditer == mActiveSounds.end()) + return; - void SoundManager::updateObject(MWWorld::Ptr ptr) - { - updatePositions(ptr); - } + const ESM::Position &pos = ptr.getCellRef().pos; + IDMap::iterator iditer = snditer->second.begin(); + while(iditer != snditer->second.end()) + { + iditer->second->update(pos.pos); + iditer++; + } + } - void SoundManager::update (float duration) - { + void SoundManager::updateRegionSound(float duration) + { MWWorld::Ptr::CellStore *current = mEnvironment.mWorld->getPlayer().getPlayer().getCell(); static int total = 0; static std::string regionName = ""; static float timePassed = 0.0; - timePassed += duration; //If the region has changed - if(!(current->cell->data.flags & current->cell->Interior) && timePassed >= 10) - { + timePassed += duration; + if((current->cell->data.flags & current->cell->Interior) || timePassed < 10) + return; + timePassed = 0; - ESM::Region test = (ESM::Region) *(mEnvironment.mWorld->getStore().regions.find(current->cell->region)); + if(regionName != current->cell->region) + { + regionName = current->cell->region; + total = 0; + } - timePassed = 0; - if (regionName != current->cell->region) + const ESM::Region *regn = mEnvironment.mWorld->getStore().regions.find(regionName); + std::vector::const_iterator soundIter; + if(total == 0) + { + soundIter = regn->soundList.begin(); + while(soundIter != regn->soundList.end()) { - regionName = current->cell->region; - total = 0; + total += (int)soundIter->chance; + soundIter++; } + if(total == 0) + return; + } + + int r = (int)(rand()/((double)RAND_MAX+1) * total); + int pos = 0; - if(test.soundList.size() > 0) + soundIter = regn->soundList.begin(); + while(soundIter != regn->soundList.end()) + { + const std::string go = soundIter->sound.toString(); + int chance = (int) soundIter->chance; + //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; + soundIter++; + if(r - pos < chance) { - std::vector::iterator soundIter = test.soundList.begin(); - //mEnvironment.mSoundManager - if(total == 0) - { - while (soundIter != test.soundList.end()) - { - int chance = (int) soundIter->chance; - //ESM::NAME32 go = soundIter->sound; - //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; - soundIter++; - total += chance; - } - } + //play sound + std::cout << "Sound: " << go <<" Chance:" << chance << "\n"; + playSound(go, 1.0f, 1.0f); + break; + } + pos += chance; + } + } - int r = rand() % total; //old random code - int pos = 0; - soundIter = test.soundList.begin(); - while (soundIter != test.soundList.end()) - { - const std::string go = soundIter->sound.toString(); - int chance = (int) soundIter->chance; - //std::cout << "Sound: " << go.name <<" Chance:" << chance << "\n"; - soundIter++; - if( r - pos < chance) - { - //play sound - std::cout << "Sound: " << go <<" Chance:" << chance << "\n"; - mEnvironment.mSoundManager->playSound(go, 20.0, 1.0); - - break; - } - pos += chance; - } + void SoundManager::updateSounds(float duration) + { + static float timePassed = 0.0; + + timePassed += duration; + if(timePassed < (1.0f/30.0f)) + return; + timePassed = 0.0f; + + // Make sure music is still playing + if(!isMusicPlaying()) + startRandomTitle(); + + Ogre::Camera *cam = mEnvironment.mWorld->getPlayer().getRenderer()->getCamera(); + Ogre::Vector3 nPos, nDir, nUp; + nPos = cam->getRealPosition(); + nDir = cam->getRealDirection(); + nUp = cam->getRealUp(); + + // The output handler is expecting vectors oriented like the game + // (that is, -Z goes down, +Y goes forward), but that's not what we + // get from Ogre's camera, so we have to convert. + float pos[3] = { nPos[0], -nPos[2], nPos[1] }; + float at[3] = { nDir[0], -nDir[2], nDir[1] }; + float up[3] = { nUp[0], -nUp[2], nUp[1] }; + mOutput->updateListener(pos, at, up); + + // Check if any sounds are finished playing, and trash them + SoundMap::iterator snditer = mActiveSounds.begin(); + while(snditer != mActiveSounds.end()) + { + IDMap::iterator iditer = snditer->second.begin(); + while(iditer != snditer->second.end()) + { + if(!iditer->second->isPlaying()) + snditer->second.erase(iditer++); + else + iditer++; } + if(snditer->second.empty()) + mActiveSounds.erase(snditer++); + else + snditer++; + } + + IDMap::iterator iditer = mLooseSounds.begin(); + while(iditer != mLooseSounds.end()) + { + if(!iditer->second->isPlaying()) + mLooseSounds.erase(iditer++); + else + iditer++; + } + } + + void SoundManager::update(float duration) + { + updateSounds(duration); + updateRegionSound(duration); + } + + + // Default readAll implementation, for decoders that can't do anything + // better + void Sound_Decoder::readAll(std::vector &output) + { + size_t total = output.size(); + size_t got; + + output.resize(total+32768); + while((got=read(&output[total], output.size()-total)) > 0) + { + total += got; + output.resize(total*2); } - else if(current->cell->data.flags & current->cell->Interior) + output.resize(total); + } + + + const char *getSampleTypeName(SampleType type) + { + switch(type) { - regionName = ""; + case SampleType_UInt8: return "U8"; + case SampleType_Int16: return "S16"; } + return "(unknown sample type)"; + } - } + const char *getChannelConfigName(ChannelConfig config) + { + switch(config) + { + case ChannelConfig_Mono: return "Mono"; + case ChannelConfig_Stereo: return "Stereo"; + } + return "(unknown channel config)"; + } + + size_t framesToBytes(size_t frames, ChannelConfig config, SampleType type) + { + switch(config) + { + case ChannelConfig_Mono: frames *= 1; break; + case ChannelConfig_Stereo: frames *= 2; break; + } + switch(type) + { + case SampleType_UInt8: frames *= 1; break; + case SampleType_Int16: frames *= 2; break; + } + return frames; + } + + size_t bytesToFrames(size_t bytes, ChannelConfig config, SampleType type) + { + return bytes / framesToBytes(1, config, type); + } } diff --git a/apps/openmw/mwsound/soundmanager.hpp b/apps/openmw/mwsound/soundmanager.hpp index dcf64b90c..b7c883a13 100644 --- a/apps/openmw/mwsound/soundmanager.hpp +++ b/apps/openmw/mwsound/soundmanager.hpp @@ -3,10 +3,7 @@ #include -#include -#include - -#include +#include #include @@ -19,16 +16,6 @@ namespace Ogre class Camera; } -namespace Mangle -{ - namespace Sound - { - typedef boost::shared_ptr SoundPtr; - } -} - -typedef OEngine::Sound::SoundManagerPtr OEManagerPtr; - namespace MWWorld { struct Environment; @@ -36,128 +23,96 @@ namespace MWWorld namespace MWSound { - class SoundManager - { + class Sound_Output; + class Sound_Decoder; + class Sound; - // This is used for case insensitive and slash-type agnostic file - // finding. It takes DOS paths (any case, \\ slashes or / slashes) - // relative to the sound dir, and translates them into full paths - // of existing files in the filesystem, if they exist. - bool mFSStrict; + typedef boost::shared_ptr DecoderPtr; - MWWorld::Environment& mEnvironment; - - void streamMusicFull (const std::string& filename); - ///< Play a soundifle - /// \param absolute filename - - /* This is the sound manager. It loades, stores and deletes - sounds based on the sound factory it is given. - */ - OEManagerPtr mgr; - Mangle::Sound::SoundPtr music; - - /* This class calls update() on the sound manager each frame - using and Ogre::FrameListener - */ - Mangle::Sound::OgreOutputUpdater updater; - - /* This class tracks the movement of an Ogre::Camera and moves - a sound listener automatically to follow it. - */ - Mangle::Sound::OgreListenerMover cameraTracker; - - typedef std::map IDMap; - typedef std::map PtrMap; - PtrMap sounds; - - // A list of all sound files used to lookup paths - Files::PathContainer mSoundFiles; + class SoundManager + { + Ogre::ResourceGroupManager& mResourceMgr; - // A library of all Music file paths stored by the folder they are contained in - Files::FileLibrary mMusicLibrary; + MWWorld::Environment& mEnvironment; - // Points to the current playlist of music files stored in the music library - const Files::PathContainer* mCurrentPlaylist; + std::auto_ptr mOutput; - IDMap mLoopedSounds; + boost::shared_ptr mMusic; + std::string mCurrentPlaylist; - bool mUsingSound; + typedef boost::shared_ptr SoundPtr; + typedef std::map IDMap; + typedef std::map SoundMap; + SoundMap mActiveSounds; + IDMap mLooseSounds; - std::string lookup(const std::string &soundId, - float &volume, float &min, float &max); - void add(const std::string &file, - MWWorld::Ptr ptr, const std::string &id, - float volume, float pitch, float min, float max, - bool loop, bool untracked=false); - void clearAll(PtrMap::iterator& it); - void remove(MWWorld::Ptr ptr, const std::string &id = ""); - bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const; - void removeCell(const MWWorld::Ptr::CellStore *cell); - void updatePositions(MWWorld::Ptr ptr); + std::string lookup(const std::string &soundId, + float &volume, float &min, float &max); + void streamMusicFull(const std::string& filename); + bool isPlaying(MWWorld::Ptr ptr, const std::string &id) const; + void updateSounds(float duration); + void updateRegionSound(float duration); - public: + SoundManager(const SoundManager &rhs); + SoundManager& operator=(const SoundManager &rhs); - SoundManager(Ogre::Root*, Ogre::Camera*, - const Files::PathContainer& dataDir, bool useSound, bool fsstrict, - MWWorld::Environment& environment); - ~SoundManager(); + protected: + DecoderPtr getDecoder(); + friend class OpenAL_Output; - void stopMusic(); - ///< Stops music if it's playing + public: + SoundManager(bool useSound, MWWorld::Environment& environment); + ~SoundManager(); - void streamMusic(const std::string& filename); - ///< Play a soundifle - /// \param filename name of a sound file in "Music/" in the data directory. + void stopMusic(); + ///< Stops music if it's playing - void startRandomTitle(); - ///< Starts a random track from the current playlist + void streamMusic(const std::string& filename); + ///< Play a soundifle + /// \param filename name of a sound file in "Music/" in the data directory. - bool isMusicPlaying(); - ///< Returns true if music is playing + void startRandomTitle(); + ///< Starts a random track from the current playlist - bool setPlaylist(std::string playlist=""); - ///< Set the playlist to an existing folder - /// \param name of the folder that contains the playlist - /// if none is set then it is set to an empty playlist - /// \return Return true if the previous playlist was the same + bool isMusicPlaying(); + ///< Returns true if music is playing - void playPlaylist(std::string playlist=""); - ///< Start playing music from the selected folder - /// \param name of the folder that contains the playlist - /// if none is set then it plays from the current playlist + void playPlaylist(const std::string &playlist); + ///< Start playing music from the selected folder + /// \param name of the folder that contains the playlist - void say (MWWorld::Ptr reference, const std::string& filename); - ///< Make an actor say some text. - /// \param filename name of a sound file in "Sound/Vo/" in the data directory. + void say(MWWorld::Ptr reference, const std::string& filename); + ///< Make an actor say some text. + /// \param filename name of a sound file in "Sound/Vo/" in the data directory. - bool sayDone (MWWorld::Ptr reference) const; - ///< Is actor not speaking? + bool sayDone(MWWorld::Ptr reference) const; + ///< Is actor not speaking? - void playSound (const std::string& soundId, float volume, float pitch, bool loop=false); - ///< Play a sound, independently of 3D-position + void playSound(const std::string& soundId, float volume, float pitch, bool loop=false); + ///< Play a sound, independently of 3D-position - void playSound3D (MWWorld::Ptr reference, const std::string& soundId, - float volume, float pitch, bool loop, bool untracked=false); - ///< Play a sound from an object + void playSound3D(MWWorld::Ptr reference, const std::string& soundId, + float volume, float pitch, bool loop, + bool untracked=false); + ///< Play a sound from an object - void stopSound3D (MWWorld::Ptr reference, const std::string& soundId = ""); - ///< Stop the given object from playing the given sound, If no soundId is given, - /// all sounds for this reference will stop. + void stopSound3D(MWWorld::Ptr reference, const std::string& soundId=""); + ///< Stop the given object from playing the given sound, If no soundId is given, + /// all sounds for this reference will stop. - void stopSound (MWWorld::Ptr::CellStore *cell); - ///< Stop all sounds for the given cell. + void stopSound(MWWorld::Ptr::CellStore *cell); + ///< Stop all sounds for the given cell. - void stopSound(const std::string& soundId); - ///< Stop a non-3d looping sound + void stopSound(const std::string& soundId); + ///< Stop a non-3d looping sound - bool getSoundPlaying (MWWorld::Ptr reference, const std::string& soundId) const; - ///< Is the given sound currently playing on the given object? + bool getSoundPlaying(MWWorld::Ptr reference, const std::string& soundId) const; + ///< Is the given sound currently playing on the given object? - void updateObject(MWWorld::Ptr reference); - ///< Update the position of all sounds connected to the given object. + void updateObject(MWWorld::Ptr reference); + ///< Update the position of all sounds connected to the given object. - void update (float duration); + void update(float duration); }; } diff --git a/files/launcher.qss b/files/launcher.qss index dad87022c..8be235f71 100644 --- a/files/launcher.qss +++ b/files/launcher.qss @@ -22,7 +22,7 @@ stop:0.9 rgba(0, 0, 0, 55), stop:1 rgba(0, 0, 0, 100)); - font: 24pt "Trebuchet MS"; + font: 26pt "EB Garamond"; color: black; border-right: 1px solid rgba(0, 0, 0, 155); @@ -54,7 +54,7 @@ } #ProfileLabel { - font: 14pt "Trebuchet MS"; + font: 18pt "EB Garamond"; } #ProfilesComboBox { @@ -82,7 +82,7 @@ padding-top: 3px; padding-left: 4px; - font: 11pt "Trebuchet MS"; + font: 12pt "EB Garamond"; } #ProfilesComboBox::drop-down { diff --git a/files/mygui/CMakeLists.txt b/files/mygui/CMakeLists.txt index 9a6cde7ba..dbc20f3f8 100644 --- a/files/mygui/CMakeLists.txt +++ b/files/mygui/CMakeLists.txt @@ -6,7 +6,6 @@ set(DDIR ${OpenMW_BINARY_DIR}/resources/mygui) configure_file("${SDIR}/bigbars.png" "${DDIR}/bigbars.png" COPYONLY) configure_file("${SDIR}/black.png" "${DDIR}/black.png" COPYONLY) -configure_file("${SDIR}/Comic.TTF" "${DDIR}/Comic.TTF" COPYONLY) configure_file("${SDIR}/core.skin" "${DDIR}/core.skin" COPYONLY) configure_file("${SDIR}/core.xml" "${DDIR}/core.xml" COPYONLY) configure_file("${SDIR}/mwpointer.png" "${DDIR}/mwpointer.png" COPYONLY) @@ -54,4 +53,5 @@ configure_file("${SDIR}/openmw_journal_layout.xml" "${DDIR}/openmw_journal_layou configure_file("${SDIR}/openmw_journal_skin.xml" "${DDIR}/openmw_journal_skin.xml" COPYONLY) configure_file("${SDIR}/smallbars.png" "${DDIR}/smallbars.png" COPYONLY) configure_file("${SDIR}/transparent.png" "${DDIR}/transparent.png" COPYONLY) +configure_file("${SDIR}/EBGaramond-Regular.ttf" "${DDIR}/EBGaramond-Regular.ttf" COPYONLY) configure_file("${SDIR}/VeraMono.ttf" "${DDIR}/VeraMono.ttf" COPYONLY) diff --git a/files/mygui/Comic.TTF b/files/mygui/Comic.TTF deleted file mode 100644 index 309894baf..000000000 Binary files a/files/mygui/Comic.TTF and /dev/null differ diff --git a/files/mygui/EBGaramond-Regular.ttf b/files/mygui/EBGaramond-Regular.ttf new file mode 100644 index 000000000..dde486903 Binary files /dev/null and b/files/mygui/EBGaramond-Regular.ttf differ diff --git a/files/mygui/core.skin b/files/mygui/core.skin index 28838c234..e52080fe0 100644 --- a/files/mygui/core.skin +++ b/files/mygui/core.skin @@ -2,11 +2,11 @@ - - + + - + diff --git a/files/mygui/core.xml b/files/mygui/core.xml index 5bec13aef..7417328cf 100644 --- a/files/mygui/core.xml +++ b/files/mygui/core.xml @@ -1,28 +1,26 @@ - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/files/mygui/openmw.font.xml b/files/mygui/openmw.font.xml index 454c3caec..e7d0f50c8 100644 --- a/files/mygui/openmw.font.xml +++ b/files/mygui/openmw.font.xml @@ -1,95 +1,40 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/files/mygui/openmw_button.skin.xml b/files/mygui/openmw_button.skin.xml index 0533a360f..1c6893026 100644 --- a/files/mygui/openmw_button.skin.xml +++ b/files/mygui/openmw_button.skin.xml @@ -45,10 +45,7 @@ - - - - + diff --git a/files/mygui/openmw_console.skin.xml b/files/mygui/openmw_console.skin.xml index 1c8740ede..598252734 100644 --- a/files/mygui/openmw_console.skin.xml +++ b/files/mygui/openmw_console.skin.xml @@ -2,8 +2,6 @@ - - diff --git a/files/mygui/openmw_dialogue_window_layout.xml b/files/mygui/openmw_dialogue_window_layout.xml index 6e833004b..11ac41cb3 100644 --- a/files/mygui/openmw_dialogue_window_layout.xml +++ b/files/mygui/openmw_dialogue_window_layout.xml @@ -12,7 +12,6 @@ - @@ -21,8 +20,8 @@ - + align="Right Top" name="Disposition"> + diff --git a/files/mygui/openmw_edit.skin.xml b/files/mygui/openmw_edit.skin.xml index 609dfe2c8..a86317d62 100644 --- a/files/mygui/openmw_edit.skin.xml +++ b/files/mygui/openmw_edit.skin.xml @@ -11,8 +11,7 @@ - - + @@ -33,8 +32,7 @@ - - + @@ -51,7 +49,7 @@ - + diff --git a/files/mygui/openmw_interactive_messagebox_layout.xml b/files/mygui/openmw_interactive_messagebox_layout.xml index 4ef2243d4..744f21227 100644 --- a/files/mygui/openmw_interactive_messagebox_layout.xml +++ b/files/mygui/openmw_interactive_messagebox_layout.xml @@ -3,14 +3,13 @@ + + + - - - - diff --git a/files/mygui/openmw_journal_skin.xml b/files/mygui/openmw_journal_skin.xml index a0d6ee2e8..0ef87852f 100644 --- a/files/mygui/openmw_journal_skin.xml +++ b/files/mygui/openmw_journal_skin.xml @@ -14,13 +14,13 @@ - + - + diff --git a/files/mygui/openmw_list.skin.xml b/files/mygui/openmw_list.skin.xml index 98390367c..0ac8e03ba 100644 --- a/files/mygui/openmw_list.skin.xml +++ b/files/mygui/openmw_list.skin.xml @@ -167,8 +167,7 @@ - - + @@ -177,10 +176,9 @@ - - + - + diff --git a/files/mygui/openmw_messagebox_layout.xml b/files/mygui/openmw_messagebox_layout.xml index 244f58c99..81d1c0a57 100644 --- a/files/mygui/openmw_messagebox_layout.xml +++ b/files/mygui/openmw_messagebox_layout.xml @@ -6,14 +6,13 @@ + + + - - - - diff --git a/files/mygui/openmw_progress.skin.xml b/files/mygui/openmw_progress.skin.xml index a5fbfb0a3..c4b94e28e 100644 --- a/files/mygui/openmw_progress.skin.xml +++ b/files/mygui/openmw_progress.skin.xml @@ -19,11 +19,10 @@ - - + - + diff --git a/files/mygui/openmw_settings.xml b/files/mygui/openmw_settings.xml index ca62294de..c63f962fb 100644 --- a/files/mygui/openmw_settings.xml +++ b/files/mygui/openmw_settings.xml @@ -1,9 +1,9 @@ - - + + diff --git a/files/mygui/openmw_text.skin.xml b/files/mygui/openmw_text.skin.xml index d62a5b8c0..6ae14c558 100644 --- a/files/mygui/openmw_text.skin.xml +++ b/files/mygui/openmw_text.skin.xml @@ -2,40 +2,35 @@ - - + - - + - - + - - + - - + @@ -45,8 +40,7 @@ - - + diff --git a/files/mygui/openmw_windows.skin.xml b/files/mygui/openmw_windows.skin.xml index ea8eb5330..a986dcffc 100644 --- a/files/mygui/openmw_windows.skin.xml +++ b/files/mygui/openmw_windows.skin.xml @@ -189,14 +189,7 @@ - - - + @@ -221,8 +214,7 @@ ------------------------------------------------------ --> - - + @@ -298,8 +290,7 @@ - - + diff --git a/libs/mangle/sound/.gitignore b/libs/mangle/sound/.gitignore deleted file mode 100644 index 8b1378917..000000000 --- a/libs/mangle/sound/.gitignore +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libs/mangle/sound/clients/ogre_listener_mover.hpp b/libs/mangle/sound/clients/ogre_listener_mover.hpp deleted file mode 100644 index 74c21db32..000000000 --- a/libs/mangle/sound/clients/ogre_listener_mover.hpp +++ /dev/null @@ -1,79 +0,0 @@ -#ifndef MANGLE_SOUND_OGRELISTENERMOVER_H -#define MANGLE_SOUND_OGRELISTENERMOVER_H - -#include -#include -#include "../output.hpp" - -namespace Mangle { -namespace Sound { - - /** This class lets a sound listener (ie. the SoundFactory) track a - given camera in Ogre3D. The position and orientation of the - listener will be updated to match the camera whenever the camera - is moved. - */ - struct OgreListenerMover : Ogre::Camera::Listener - { - OgreListenerMover(Mangle::Sound::SoundFactoryPtr snd) - : soundFact(snd), camera(NULL) - {} - - /// Follow a camera. WARNING: This will OVERRIDE any other - /// MovableObject::Listener you may have attached to the camera. - void followCamera(Ogre::Camera *cam) - { - camera = cam; - camera->addListener(this); - } - - void unfollowCamera() - { - // If the camera is null, this object wasn't following a camera. - // It doesn't make sense to call unfollow - assert(camera != NULL); - - camera->removeListener(this); - camera = NULL; - } - - private: - Mangle::Sound::SoundFactoryPtr soundFact; - Ogre::Camera *camera; - Ogre::Vector3 pos, dir, up; - - /// From Camera::Listener. This is called once per - /// frame. Unfortunately, Ogre doesn't allow us to be notified - /// only when the camera itself has moved, so we must poll every - /// frame. - void cameraPreRenderScene(Ogre::Camera *cam) - { - assert(cam == camera); - - Ogre::Vector3 nPos, nDir, nUp; - - nPos = camera->getRealPosition(); - nDir = camera->getRealDirection(); - nUp = camera->getRealUp(); - - // Don't bother the sound system needlessly - if(nDir != dir || nPos != pos || nUp != up) - { - pos = nPos; - dir = nDir; - up = nUp; - - soundFact->setListenerPos(pos.x, pos.y, pos.z, - dir.x, dir.y, dir.z, - up.x, up.y, up.z); - } - } - - void cameraDestroyed(Ogre::Camera *cam) - { - assert(cam == camera); - camera = NULL; - } - }; -}} -#endif diff --git a/libs/mangle/sound/clients/ogre_output_updater.hpp b/libs/mangle/sound/clients/ogre_output_updater.hpp deleted file mode 100644 index b73168c75..000000000 --- a/libs/mangle/sound/clients/ogre_output_updater.hpp +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef MANGLE_SOUND_OGREUPDATER_H -#define MANGLE_SOUND_OGREUPDATER_H - -/* - This Ogre FrameListener calls update on a SoundFactory - */ - -#include -#include "../output.hpp" -#include - -namespace Mangle { -namespace Sound { - - struct OgreOutputUpdater : Ogre::FrameListener - { - Mangle::Sound::SoundFactoryPtr driver; - - OgreOutputUpdater(Mangle::Sound::SoundFactoryPtr drv) - : driver(drv) - { assert(drv->needsUpdate); } - - bool frameStarted(const Ogre::FrameEvent &evt) - { - driver->update(); - return true; - } - }; -}} - -#endif diff --git a/libs/mangle/sound/filters/input_filter.hpp b/libs/mangle/sound/filters/input_filter.hpp deleted file mode 100644 index 00ee18766..000000000 --- a/libs/mangle/sound/filters/input_filter.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#ifndef MANGLE_INPUT_FILTER_H -#define MANGLE_INPUT_FILTER_H - -#include "../output.hpp" - -#include - -namespace Mangle { -namespace Sound { - -/** - @brief This filter class adds file loading capabilities to a - Sound::SoundFactory class, by associating a SampleSourceLoader with - it. - - The class takes an existing SoundFactory able to load streams, and - associates a SampleSourceLoader with it. The combined class is able - to load files directly. */ -class InputFilter : public SoundFactory -{ - protected: - SoundFactoryPtr snd; - SampleSourceLoaderPtr inp; - - public: - /// Empty constructor - InputFilter() {} - - /// Assign an input manager and a sound manager to this object - InputFilter(SoundFactoryPtr _snd, SampleSourceLoaderPtr _inp) - { set(_snd, _inp); } - - /// Assign an input manager and a sound manager to this object - void set(SoundFactoryPtr _snd, SampleSourceLoaderPtr _inp) - { - inp = _inp; - snd = _snd; - - // Set capabilities - needsUpdate = snd->needsUpdate; - has3D = snd->has3D; - canLoadStream = inp->canLoadStream; - - // Both these should be true, or the use of this class is pretty - // pointless - canLoadSource = snd->canLoadSource; - canLoadFile = inp->canLoadFile; - assert(canLoadSource && canLoadFile); - } - - virtual SoundPtr load(const std::string &file) - { return loadRaw(inp->load(file)); } - - virtual SoundPtr load(Stream::StreamPtr input) - { return loadRaw(inp->load(input)); } - - virtual SoundPtr loadRaw(SampleSourcePtr input) - { return snd->loadRaw(input); } - - virtual void update() { snd->update(); } - virtual void setListenerPos(float x, float y, float z, - float fx, float fy, float fz, - float ux, float uy, float uz) - { snd->setListenerPos(x,y,z,fx,fy,fz,ux,uy,uz); } -}; - -}} -#endif diff --git a/libs/mangle/sound/filters/openal_audiere.hpp b/libs/mangle/sound/filters/openal_audiere.hpp deleted file mode 100644 index 5b9b51824..000000000 --- a/libs/mangle/sound/filters/openal_audiere.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MANGLE_AUDIERE_OPENAL_H -#define MANGLE_AUDIERE_OPENAL_H - -#include "input_filter.hpp" -#include "../sources/audiere_source.hpp" -#include "../outputs/openal_out.hpp" - -namespace Mangle { -namespace Sound { - -/// A InputFilter that adds audiere decoding to OpenAL. Audiere has -/// it's own output, but OpenAL sports 3D and other advanced features. -class OpenAL_Audiere_Factory : public InputFilter -{ - public: - OpenAL_Audiere_Factory() - { - set(SoundFactoryPtr(new OpenAL_Factory), - SampleSourceLoaderPtr(new AudiereLoader)); - } -}; - -}} -#endif diff --git a/libs/mangle/sound/filters/openal_ffmpeg.hpp b/libs/mangle/sound/filters/openal_ffmpeg.hpp deleted file mode 100644 index 42c76af0c..000000000 --- a/libs/mangle/sound/filters/openal_ffmpeg.hpp +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef MANGLE_FFMPEG_OPENAL_H -#define MANGLE_FFMPEG_OPENAL_H - -#include "input_filter.hpp" -#include "../sources/ffmpeg_source.hpp" -#include "../outputs/openal_out.hpp" - -namespace Mangle { -namespace Sound { - -/// A InputFilter that adds ffmpeg decoding to OpenAL. -class OpenAL_FFMpeg_Factory : public InputFilter -{ - public: - OpenAL_FFMpeg_Factory() - { - set(SoundFactoryPtr(new OpenAL_Factory), - SampleSourceLoaderPtr(new FFMpegLoader)); - } -}; - -}} -#endif diff --git a/libs/mangle/sound/filters/openal_mpg123.hpp b/libs/mangle/sound/filters/openal_mpg123.hpp deleted file mode 100644 index bfd926c0b..000000000 --- a/libs/mangle/sound/filters/openal_mpg123.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MANGLE_MPG123_OPENAL_H -#define MANGLE_MPG123_OPENAL_H - -#include "input_filter.hpp" -#include "../sources/mpg123_source.hpp" -#include "../outputs/openal_out.hpp" - -namespace Mangle { -namespace Sound { - -/// A InputFilter that adds mpg123 decoding to OpenAL. Only supports -/// MP3 files. -class OpenAL_Mpg123_Factory : public InputFilter -{ - public: - OpenAL_Mpg123_Factory() - { - set(SoundFactoryPtr(new OpenAL_Factory), - SampleSourceLoaderPtr(new Mpg123Loader)); - } -}; - -}} -#endif diff --git a/libs/mangle/sound/filters/openal_sndfile.hpp b/libs/mangle/sound/filters/openal_sndfile.hpp deleted file mode 100644 index fd7e78025..000000000 --- a/libs/mangle/sound/filters/openal_sndfile.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef MANGLE_SNDFILE_OPENAL_H -#define MANGLE_SNDFILE_OPENAL_H - -#include "input_filter.hpp" -#include "../sources/libsndfile.hpp" -#include "../outputs/openal_out.hpp" - -namespace Mangle { -namespace Sound { - -/// A InputFilter that adds libsnd decoding to OpenAL. libsndfile -/// supports most formats except MP3. -class OpenAL_SndFile_Factory : public InputFilter -{ - public: - OpenAL_SndFile_Factory() - { - set(SoundFactoryPtr(new OpenAL_Factory), - SampleSourceLoaderPtr(new SndFileLoader)); - } -}; - -}} -#endif diff --git a/libs/mangle/sound/filters/openal_sndfile_mpg123.hpp b/libs/mangle/sound/filters/openal_sndfile_mpg123.hpp deleted file mode 100644 index 6e5db4d0e..000000000 --- a/libs/mangle/sound/filters/openal_sndfile_mpg123.hpp +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef MANGLE_SNDFILE_MPG123_OPENAL_H -#define MANGLE_SNDFILE_MPG123_OPENAL_H - -#include "input_filter.hpp" -#include "source_splicer.hpp" -#include "../sources/mpg123_source.hpp" -#include "../sources/libsndfile.hpp" -#include "../outputs/openal_out.hpp" - -namespace Mangle { -namespace Sound { - -/// A InputFilter that uses OpenAL for output, and mpg123 (for MP3) + -/// libsndfile (for everything else) to decode files. Can only load -/// from the file system, and uses the file name to differentiate -/// between mp3 and non-mp3 types. -class OpenAL_SndFile_Mpg123_Factory : public InputFilter -{ - public: - OpenAL_SndFile_Mpg123_Factory() - { - SourceSplicer *splice = new SourceSplicer; - - splice->add("mp3", SampleSourceLoaderPtr(new Mpg123Loader)); - splice->setDefault(SampleSourceLoaderPtr(new SndFileLoader)); - - set(SoundFactoryPtr(new OpenAL_Factory), - SampleSourceLoaderPtr(splice)); - } -}; - -}} -#endif diff --git a/libs/mangle/sound/filters/openal_various.hpp b/libs/mangle/sound/filters/openal_various.hpp deleted file mode 100644 index 945b3dabd..000000000 --- a/libs/mangle/sound/filters/openal_various.hpp +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef MANGLE_VARIOUS_OPENAL_H -#define MANGLE_VARIOUS_OPENAL_H - -#include "input_filter.hpp" -#include "source_splicer.hpp" -#include "../sources/mpg123_source.hpp" -#include "../sources/wav_source.hpp" -#include "../outputs/openal_out.hpp" - -namespace Mangle { -namespace Sound { - -/** A InputFilter that uses OpenAL for output, and load input from - various individual sources, depending on file extension. Currently - supports: - - MP3: mpg123 - WAV: custom wav loader (PCM only) - - This could be an alternative to using eg. 3rd party decoder - libraries like libsndfile. - */ -class OpenAL_Various_Factory : public InputFilter -{ - public: - OpenAL_Various_Factory() - { - SourceSplicer *splice = new SourceSplicer; - - splice->add("mp3", SampleSourceLoaderPtr(new Mpg123Loader)); - splice->add("wav", SampleSourceLoaderPtr(new WavLoader)); - - set(SoundFactoryPtr(new OpenAL_Factory), - SampleSourceLoaderPtr(splice)); - } -}; - -}} -#endif diff --git a/libs/mangle/sound/filters/pure_filter.hpp b/libs/mangle/sound/filters/pure_filter.hpp deleted file mode 100644 index fc5e62574..000000000 --- a/libs/mangle/sound/filters/pure_filter.hpp +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef MANGLE_SOUND_OUTPUT_PUREFILTER_H -#define MANGLE_SOUND_OUTPUT_PUREFILTER_H - -#include "../output.hpp" - -namespace Mangle -{ - namespace Sound - { - // For use in writing other filters - class SoundFilter : public Sound - { - protected: - SoundPtr client; - - public: - SoundFilter(SoundPtr c) : client(c) {} - void play() { client->play(); } - void stop() { client->stop(); } - void pause() { client->pause(); } - bool isPlaying() const { return client->isPlaying(); } - void setVolume(float f) { client->setVolume(f); } - void setPan(float f) { client->setPan(f); } - void setPos(float x, float y, float z) - { client->setPos(x,y,z); } - void setPitch(float p) { client->setPitch(p); } - void setRepeat(bool b) { client->setRepeat(b); } - void setRange(float a, float b=0, float c=0) - { client->setRange(a,b,c); } - void setStreaming(bool b) { client->setStreaming(b); } - void setRelative(bool b) { client->setRelative(b); } - - // The clone() function is not implemented here, as you will - // almost certainly want to override it yourself - }; - - class FactoryFilter : public SoundFactory - { - protected: - SoundFactoryPtr client; - - public: - FactoryFilter(SoundFactoryPtr c) : client(c) - { - needsUpdate = client->needsUpdate; - has3D = client->has3D; - canLoadFile = client->canLoadFile; - canLoadStream = client->canLoadStream; - canLoadSource = client->canLoadSource; - } - - SoundPtr loadRaw(SampleSourcePtr input) - { return client->loadRaw(input); } - - SoundPtr load(Stream::StreamPtr input) - { return client->load(input); } - - SoundPtr load(const std::string &file) - { return client->load(file); } - - void update() - { client->update(); } - - void setListenerPos(float x, float y, float z, - float fx, float fy, float fz, - float ux, float uy, float uz) - { - client->setListenerPos(x,y,z,fx,fy,fz,ux,uy,uz); - } - }; - } -} -#endif diff --git a/libs/mangle/sound/filters/source_splicer.hpp b/libs/mangle/sound/filters/source_splicer.hpp deleted file mode 100644 index 9c7623086..000000000 --- a/libs/mangle/sound/filters/source_splicer.hpp +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef MANGLE_SOUND_SOURCE_SPLICE_H -#define MANGLE_SOUND_SOURCE_SPLICE_H - -#include "../source.hpp" -#include -#include -#include -#include - -namespace Mangle -{ - namespace Sound - { - class SourceSplicer : public SampleSourceLoader - { - struct SourceType - { - std::string type; - SampleSourceLoaderPtr loader; - }; - - typedef std::list TypeList; - TypeList list; - SampleSourceLoaderPtr catchAll; - - static bool isMatch(char a, char b) - { - if(a >= 'A' && a <= 'Z') - a += 'a' - 'A'; - if(b >= 'A' && b <= 'Z') - b += 'a' - 'A'; - return a == b; - } - - public: - SourceSplicer() - { - canLoadStream = false; - canLoadFile = true; - } - - void add(const std::string &type, SampleSourceLoaderPtr fact) - { - SourceType tp; - tp.type = type; - tp.loader = fact; - list.push_back(tp); - } - - void setDefault(SampleSourceLoaderPtr def) - { - catchAll = def; - } - - SampleSourcePtr load(const std::string &file) - { - // Search the list for this file type. - for(TypeList::iterator it = list.begin(); - it != list.end(); it++) - { - const std::string &t = it->type; - - int diff = file.size() - t.size(); - if(diff < 0) continue; - - bool match = true; - for(unsigned i=0; iloader->load(file); - } - // If not found, use the catch-all - if(catchAll) - return catchAll->load(file); - - throw std::runtime_error("No handler for sound file " + file); - } - - SampleSourcePtr load(Stream::StreamPtr input) { assert(0); } - }; - } -} - -#endif diff --git a/libs/mangle/sound/output.hpp b/libs/mangle/sound/output.hpp deleted file mode 100644 index e30bf21e2..000000000 --- a/libs/mangle/sound/output.hpp +++ /dev/null @@ -1,183 +0,0 @@ -#ifndef MANGLE_SOUND_OUTPUT_H -#define MANGLE_SOUND_OUTPUT_H - -#include -#include - -#include "source.hpp" -#include "../stream/stream.hpp" - -namespace Mangle { -namespace Sound { - -/// Abstract interface for a single playable sound -/** This class represents one sound outlet, which may be played, - stopped, paused and so on. - - Sound instances are created from the SoundFactory class. Sounds - may be connected to a SampleSource or read directly from a file, - and they may support 3d sounds, looping and other features - depending on the capabilities of the backend system. - - To create multiple instances of one sound, it is recommended to - 'clone' an existing instance instead of reloading it from - file. Cloned sounds will often (depending on the back-end) use - less memory due to shared buffers. -*/ -class Sound; -typedef boost::shared_ptr SoundPtr; -typedef boost::weak_ptr WSoundPtr; - -class Sound -{ - public: - /// Play or resume the sound - virtual void play() = 0; - - /// Stop the sound - virtual void stop() = 0; - - /// Pause the sound, may be resumed later - virtual void pause() = 0; - - /// Check if the sound is still playing - virtual bool isPlaying() const = 0; - - /// Set the volume. The parameter must be between 0.0 and 1.0. - virtual void setVolume(float) = 0; - - /// Set left/right pan. -1.0 is left, 0.0 is center and 1.0 is right. - virtual void setPan(float) = 0; - - /// Set pitch (1.0 is normal speed) - virtual void setPitch(float) = 0; - - /// Set range factors for 3D sounds. The meaning of the fields - /// depend on implementation. - virtual void setRange(float a, float b=0.0, float c=0.0) = 0; - - /// Set the position. May not work with all backends. - virtual void setPos(float x, float y, float z) = 0; - - /// Set loop mode - virtual void setRepeat(bool) = 0; - - /// If set to true the sound will not be affected by player movement - virtual void setRelative(bool) = 0; - - /// Set streaming mode. - /** This may be used by implementations to optimize for very large - files. If streaming mode is off (default), most implementations - will load the entire file into memory before starting playback. - */ - virtual void setStreaming(bool) = 0; - - /// Create a new instance of this sound. - /** Playback status is not cloned, only the sound data - itself. Back-ends can use this as a means of sharing data and - saving memory. */ - virtual SoundPtr clone() = 0; - - /// Virtual destructor - virtual ~Sound() {} -}; - -/// Factory interface for creating Sound objects -/** The SoundFactory is the main entry point to a given sound output - system. It is used to create Sound objects, which may be connected - to a sound file or stream, and which may be individually played, - paused, and so on. - - The class also contains a set of public bools which describe the - capabilities the particular system. These should be set by - implementations (base classes) in their respective constructors. - */ -class SoundFactory -{ - public: - /// Virtual destructor - virtual ~SoundFactory() {} - - /** @brief If set to true, you should call update() regularly (every frame - or so) on this sound manager. If false, update() should not be - called. - */ - bool needsUpdate; - - /** @brief true if 3D functions are available. If false, all use of - 3D sounds and calls to setPos / setListenerPos will result in - undefined behavior. - */ - bool has3D; - - /// true if we can load sounds directly from file (containing encoded data) - bool canLoadFile; - - /// If true, we can lound sound files from a Stream (containing encoded data) - bool canLoadStream; - - /// true if we can load sounds from a SampleSource (containing raw data) - bool canLoadSource; - - /** - @brief Load a sound from a sample source. Only valid if - canLoadSource is true. - - This function loads a sound from a given stream as defined by - SampleSource. - - @param input the input source - @param stream true if the file should be streamed. - Implementations may use this for optimizing playback of - large files, but they are not required to. - @return a new Sound object - */ - virtual SoundPtr loadRaw(SampleSourcePtr input) = 0; - - /** - @brief Load a sound file from stream. Only valid if canLoadStream - is true. - - @param input audio file stream - @param stream true if the file should be streamed - @see load(InputSource*,bool) - */ - virtual SoundPtr load(Stream::StreamPtr input) = 0; - - /** - @brief Load a sound directly from file. Only valid if canLoadFile - is true. - - @param file filename - @param stream true if the file should be streamed - @see load(InputSource*,bool) - */ - virtual SoundPtr load(const std::string &file) = 0; - - /// Call this every frame if needsUpdate is true - /** - This should be called regularly (about every frame in a normal - game setting.) Implementions may use this for filling streaming - buffers and similar tasks. Implementations that do not need this - should set needsUpdate to false. - */ - virtual void update() { assert(0); } - - /// Set listener position (coordinates, front and up vectors) - /** - Only valid if has3D is true. - - @param x,y,z listener position - @param fx,fy,fz listener's looking direction - @param ux,uy,uz listener's up direction - */ - virtual void setListenerPos(float x, float y, float z, - float fx, float fy, float fz, - float ux, float uy, float uz) = 0; -}; - -typedef boost::shared_ptr SoundFactoryPtr; - -}} // Namespaces - -#endif diff --git a/libs/mangle/sound/outputs/openal_out.cpp b/libs/mangle/sound/outputs/openal_out.cpp deleted file mode 100644 index 2056b4f60..000000000 --- a/libs/mangle/sound/outputs/openal_out.cpp +++ /dev/null @@ -1,500 +0,0 @@ -#include "openal_out.hpp" -#include -#include - -#include "../../stream/filters/buffer_stream.hpp" - -#ifdef _WIN32 -#include -#include -#elif defined(__APPLE__) -#include -#include -#else -#include -#include -#endif - -using namespace Mangle::Sound; - -// ---- Helper functions and classes ---- - -// Static buffer used to shuffle sound data from the input into -// OpenAL. The data is only stored temporarily and then immediately -// shuffled off to the library. This is not thread safe, but it works -// fine with multiple sounds in one thread. It could be made thread -// safe simply by using thread local storage. -const size_t BSIZE = 32*1024; -static char tmp_buffer[BSIZE]; - -// Number of buffers used (per sound) for streaming sounds. Each -// buffer is of size BSIZE. Increasing this will make streaming sounds -// more fault tolerant against temporary lapses in call to update(), -// but will also increase memory usage. -// This was changed from 4 to 150 for an estimated 30 seconds tolerance. -// At some point we should replace it with a more multithreading-ish -// solution. -const int STREAM_BUF_NUM = 150; - -static void fail(const std::string &msg) -{ throw std::runtime_error("OpenAL exception: " + msg); } - -/* - Check for AL error. Since we're always calling this with string - literals, and it only makes sense to optimize for the non-error - case, the parameter is const char* rather than std::string. - - This way we don't force the compiler to create a string object each - time we're called (since the string is never used unless there's an - error), although a good compiler might have optimized that away in - any case. - */ -static void checkALError(const char *where) -{ - ALenum err = alGetError(); - if(err != AL_NO_ERROR) - { - std::string msg = where; - - const ALchar* errmsg = alGetString(err); - if(errmsg) - fail("\"" + std::string(alGetString(err)) + "\" while " + msg); - else - fail("non-specified error while " + msg + " (did you forget to initialize OpenAL?)"); - } -} - -static void getALFormat(SampleSourcePtr inp, int &fmt, int &rate) -{ - boost::int32_t rate_, ch, bits; - inp->getInfo(&rate_, &ch, &bits); - rate = rate_; - - fmt = 0; - - if(bits == 8) - { - if(ch == 1) fmt = AL_FORMAT_MONO8; - if(ch == 2) fmt = AL_FORMAT_STEREO8; - if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(ch == 4) fmt = alGetEnumValue("AL_FORMAT_QUAD8"); - if(ch == 6) fmt = alGetEnumValue("AL_FORMAT_51CHN8"); - } - } - if(bits == 16) - { - if(ch == 1) fmt = AL_FORMAT_MONO16; - if(ch == 2) fmt = AL_FORMAT_STEREO16; - if(ch == 4) fmt = alGetEnumValue("AL_FORMAT_QUAD16"); - if(alIsExtensionPresent("AL_EXT_MCFORMATS")) - { - if(ch == 4) fmt = alGetEnumValue("AL_FORMAT_QUAD16"); - if(ch == 6) fmt = alGetEnumValue("AL_FORMAT_51CHN16"); - } - } - - if(fmt == 0) - fail("Unsupported input format"); -} - -/// OpenAL sound output -class Mangle::Sound::OpenAL_Sound : public Sound -{ - ALuint inst; - - // Buffers. Only the first is used for non-streaming sounds. - ALuint bufferID[STREAM_BUF_NUM]; - - // Number of buffers used - int bufNum; - - // Parameters used for filling buffers - int fmt, rate; - - // Poor mans reference counting. Might improve this later. When - // NULL, the buffer has not been set up yet. - int *refCnt; - - bool streaming; - - // Input stream - SampleSourcePtr input; - - OpenAL_Factory *owner; - bool ownerAlive; - - // Used for streamed sound list - OpenAL_Sound *next, *prev; - - void setupBuffer(); - - // Fill data into the given buffer and queue it, if there is any - // data left to queue. Assumes the buffer is already unqueued, if - // necessary. - void queueBuffer(ALuint buf) - { - // If there is no more data, do nothing - if(!input) return; - if(input->eof()) - { - input.reset(); - return; - } - - // Get some new data - size_t bytes = input->read(tmp_buffer, BSIZE); - if(bytes == 0) - { - input.reset(); - return; - } - - // Move data into the OpenAL buffer - alBufferData(buf, fmt, tmp_buffer, bytes, rate); - // Queue it - alSourceQueueBuffers(inst, 1, &buf); - checkALError("Queueing buffer data"); - } - - public: - /// Read samples from the given input buffer - OpenAL_Sound(SampleSourcePtr input, OpenAL_Factory *fact); - - /// Play an existing buffer, with a given ref counter. Used - /// internally for cloning. - OpenAL_Sound(ALuint buf, int *ref, OpenAL_Factory *fact); - - ~OpenAL_Sound(); - - // Must be called regularly on streamed sounds - void update() - { - if(!streaming) return; - if(!input) return; - - // Get the number of processed buffers - ALint count; - alGetSourcei(inst, AL_BUFFERS_PROCESSED, &count); - checkALError("getting number of unprocessed buffers"); - - for(int i=0; iupdate(); -} - -void OpenAL_Factory::notifyStreaming(OpenAL_Sound *snd) -{ - // Add the sound to the streaming list - streaming.push_back(snd); -} - -void OpenAL_Factory::notifyDelete(OpenAL_Sound *snd) -{ - // Remove the sound from the stream list - streaming.remove(snd); -} - -OpenAL_Factory::~OpenAL_Factory() -{ - // Notify remaining streamed sounds that we're dying - StreamList::iterator it = streaming.begin(); - for(;it != streaming.end(); it++) - (*it)->notifyOwnerDeath(); - - // Deinitialize sound system - if(didSetup) - { - alcMakeContextCurrent(NULL); - if(context) alcDestroyContext((ALCcontext*)context); - if(device) alcCloseDevice((ALCdevice*)device); - } -} - -// ---- OpenAL_Sound ---- - -void OpenAL_Sound::play() -{ - setupBuffer(); - alSourcePlay(inst); - checkALError("starting playback"); -} - -void OpenAL_Sound::stop() -{ - alSourceStop(inst); - checkALError("stopping"); -} - -void OpenAL_Sound::pause() -{ - alSourcePause(inst); - checkALError("pausing"); -} - -bool OpenAL_Sound::isPlaying() const -{ - ALint state; - alGetSourcei(inst, AL_SOURCE_STATE, &state); - - return state == AL_PLAYING; -} - -void OpenAL_Sound::setVolume(float volume) -{ - if(volume > 1.0) volume = 1.0; - if(volume < 0.0) volume = 0.0; - alSourcef(inst, AL_GAIN, volume); - checkALError("setting volume"); -} - -void OpenAL_Sound::setRange(float a, float b, float) -{ - alSourcef(inst, AL_REFERENCE_DISTANCE, a); - alSourcef(inst, AL_MAX_DISTANCE, b); - checkALError("setting sound ranges"); -} - -void OpenAL_Sound::setPos(float x, float y, float z) -{ - alSource3f(inst, AL_POSITION, x, y, z); - checkALError("setting position"); -} - -void OpenAL_Sound::setPitch(float pitch) -{ - alSourcef(inst, AL_PITCH, pitch); - checkALError("setting pitch"); -} - -void OpenAL_Sound::setRepeat(bool rep) -{ - alSourcei(inst, AL_LOOPING, rep?AL_TRUE:AL_FALSE); -} - -void OpenAL_Sound::setRelative(bool rel) -{ - alSourcei(inst, AL_SOURCE_RELATIVE, rel?AL_TRUE:AL_FALSE); - checkALError("setting relative"); -} - -SoundPtr OpenAL_Sound::clone() -{ - setupBuffer(); - assert(!streaming && "cloning streamed sounds not supported"); - return SoundPtr(new OpenAL_Sound(bufferID[0], refCnt, owner)); -} - -// Constructor used for cloned sounds -OpenAL_Sound::OpenAL_Sound(ALuint buf, int *ref, OpenAL_Factory *fact) - : refCnt(ref), streaming(false), owner(fact), ownerAlive(false) -{ - // Increase the reference count - assert(ref != NULL); - (*refCnt)++; - - // Set up buffer - bufferID[0] = buf; - bufNum = 1; - - // Create a source - alGenSources(1, &inst); - checkALError("creating instance (clone)"); - alSourcei(inst, AL_BUFFER, bufferID[0]); - checkALError("assigning buffer (clone)"); -} - -// Constructor used for original (non-cloned) sounds -OpenAL_Sound::OpenAL_Sound(SampleSourcePtr _input, OpenAL_Factory *fact) - : refCnt(NULL), streaming(false), input(_input), owner(fact), ownerAlive(false) -{ - // Create a source - alGenSources(1, &inst); - checkALError("creating source"); - - // By default, the sound starts out in a buffer-less mode. We don't - // create a buffer until the sound is played. This gives the user - // the chance to call setStreaming(true) first. -} - -void OpenAL_Sound::setupBuffer() -{ - if(refCnt != NULL) return; - - assert(input); - - // Get the format - getALFormat(input, fmt, rate); - - // Create a cheap reference counter for the buffer - refCnt = new int; - *refCnt = 1; - - if(streaming) bufNum = STREAM_BUF_NUM; - else bufNum = 1; - - // Set up the OpenAL buffer(s) - alGenBuffers(bufNum, bufferID); - checkALError("generating buffer(s)"); - assert(bufferID[0] != 0); - - // STREAMING. - if(streaming) - { - // Just queue all the buffers with data and exit. queueBuffer() - // will work correctly also in the case where there is not - // enough data to fill all the buffers. - for(int i=0; inotifyStreaming(this); - ownerAlive = true; - - return; - } - - // NON-STREAMING. We have to load all the data and shove it into the - // buffer. - - // Does the stream support pointer operations? - if(input->hasPtr) - { - // If so, we can read the data directly from the stream - alBufferData(bufferID[0], fmt, input->getPtr(), input->size(), rate); - } - else - { - // Read the entire stream into a temporary buffer first - Mangle::Stream::BufferStream buf(input, 128*1024); - - // Then copy that into OpenAL - alBufferData(bufferID[0], fmt, buf.getPtr(), buf.size(), rate); - } - checkALError("loading sound data"); - - // We're done with the input stream, release the pointer - input.reset(); - - alSourcei(inst, AL_BUFFER, bufferID[0]); - checkALError("assigning buffer"); -} - -OpenAL_Sound::~OpenAL_Sound() -{ - // Stop - alSourceStop(inst); - - // Return sound - alDeleteSources(1, &inst); - - // Notify the factory that we quit. You will hear from our union - // rep. The bool check is to handle cases where the manager goes out - // of scope before the sounds do. In that case, don't try to contact - // the factory. - if(ownerAlive) - owner->notifyDelete(this); - - // Decrease the reference counter - if((-- (*refCnt)) == 0) - { - // We're the last owner. Delete the buffer(s) and the counter - // itself. - alDeleteBuffers(bufNum, bufferID); - checkALError("deleting buffer"); - delete refCnt; - } -} diff --git a/libs/mangle/sound/outputs/openal_out.hpp b/libs/mangle/sound/outputs/openal_out.hpp deleted file mode 100644 index 44d03ecf8..000000000 --- a/libs/mangle/sound/outputs/openal_out.hpp +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef MANGLE_SOUND_OPENAL_OUT_H -#define MANGLE_SOUND_OPENAL_OUT_H - -#include "../output.hpp" -#include - -namespace Mangle { -namespace Sound { - -class OpenAL_Sound; - -class OpenAL_Factory : public SoundFactory -{ - void *device; - void *context; - bool didSetup; - - // List of streaming sounds that need to be updated every frame. - typedef std::list StreamList; - StreamList streaming; - - friend class OpenAL_Sound; - void notifyStreaming(OpenAL_Sound*); - void notifyDelete(OpenAL_Sound*); - - public: - /// Initialize object. Pass true (default) if you want the - /// constructor to set up the current ALCdevice and ALCcontext for - /// you. - OpenAL_Factory(bool doSetup = true); - ~OpenAL_Factory(); - - SoundPtr load(const std::string &file) { assert(0); return SoundPtr(); } - SoundPtr load(Stream::StreamPtr input) { assert(0); return SoundPtr(); } - SoundPtr loadRaw(SampleSourcePtr input); - - void update(); - void setListenerPos(float x, float y, float z, - float fx, float fy, float fz, - float ux, float uy, float uz); -}; - -}} // namespaces -#endif diff --git a/libs/mangle/sound/source.hpp b/libs/mangle/sound/source.hpp deleted file mode 100644 index fbe7cf958..000000000 --- a/libs/mangle/sound/source.hpp +++ /dev/null @@ -1,62 +0,0 @@ -#ifndef MANGLE_SOUND_SOURCE_H -#define MANGLE_SOUND_SOURCE_H - -#include -#include -#include - -#include "../stream/stream.hpp" - -namespace Mangle { -namespace Sound { - -typedef boost::int32_t int32_t; - -/// A stream containing raw sound data and information about the format -class SampleSource : public Stream::Stream -{ - protected: - bool isEof; - - public: - SampleSource() : isEof(false) {} - - /// Get the sample rate, number of channels, and bits per - /// sample. NULL parameters are ignored. - virtual void getInfo(int32_t *rate, int32_t *channels, int32_t *bits) = 0; - - bool eof() const { return isEof; } - - // Disabled functions by default. You can still override them in - // subclasses. - void seek(size_t pos) { assert(0); } - size_t tell() const { assert(0); return 0; } - size_t size() const { assert(0); return 0; } -}; - -typedef boost::shared_ptr SampleSourcePtr; - -/// A factory interface for loading SampleSources from file or stream -class SampleSourceLoader -{ - public: - /// If true, the stream version of load() works - bool canLoadStream; - - /// If true, the file version of load() works - bool canLoadFile; - - /// Load a sound input source from file (if canLoadFile is true) - virtual SampleSourcePtr load(const std::string &file) = 0; - - /// Load a sound input source from stream (if canLoadStream is true) - virtual SampleSourcePtr load(Stream::StreamPtr input) = 0; - - /// Virtual destructor - virtual ~SampleSourceLoader() {} -}; - -typedef boost::shared_ptr SampleSourceLoaderPtr; - -}} // namespaces -#endif diff --git a/libs/mangle/sound/sources/audiere_source.cpp b/libs/mangle/sound/sources/audiere_source.cpp deleted file mode 100644 index faaa3c8c5..000000000 --- a/libs/mangle/sound/sources/audiere_source.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include "audiere_source.hpp" - -#include "../../stream/clients/audiere_file.hpp" - -#include - -using namespace Mangle::Stream; - -static void fail(const std::string &msg) -{ throw std::runtime_error("Audiere exception: " + msg); } - -using namespace audiere; -using namespace Mangle::Sound; - -// --- SampleSource --- - -void AudiereSource::getInfo(Mangle::Sound::int32_t *rate, - Mangle::Sound::int32_t *channels, Mangle::Sound::int32_t *bits) -{ - SampleFormat fmt; - int channels_, rate_; - sample->getFormat(channels_, rate_, fmt); - *channels = channels_; - *rate = rate_; - if(bits) - { - if(fmt == SF_U8) - *bits = 8; - else if(fmt == SF_S16) - *bits = 16; - else assert(0); - } -} - -// --- Constructors --- - -AudiereSource::AudiereSource(const std::string &file) -{ - sample = OpenSampleSource(file.c_str()); - - if(!sample) - fail("Couldn't load file " + file); - - doSetup(); -} - -AudiereSource::AudiereSource(StreamPtr input) -{ - // Use our Stream::AudiereFile implementation to convert a Mangle - // 'Stream' to an Audiere 'File' - sample = OpenSampleSource(new AudiereFile(input)); - if(!sample) - fail("Couldn't load stream"); - - doSetup(); -} - -AudiereSource::AudiereSource(audiere::SampleSourcePtr src) - : sample(src) -{ assert(sample); doSetup(); } - -// Common function called from all constructors -void AudiereSource::doSetup() -{ - assert(sample); - - SampleFormat fmt; - int channels, rate; - sample->getFormat(channels, rate, fmt); - - // Calculate the size of one frame, and pass it to SampleReader. - setup(GetSampleSize(fmt) * channels); - - isSeekable = sample->isSeekable(); - hasPosition = true; - hasSize = true; -} diff --git a/libs/mangle/sound/sources/audiere_source.hpp b/libs/mangle/sound/sources/audiere_source.hpp deleted file mode 100644 index d797c55c8..000000000 --- a/libs/mangle/sound/sources/audiere_source.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef MANGLE_SOUND_AUDIERE_SOURCE_H -#define MANGLE_SOUND_AUDIERE_SOURCE_H - -#include "sample_reader.hpp" - -// audiere.h from 1.9.4 (latest) release uses -// cstring routines like strchr() and strlen() without -// including cstring itself. -#include -#include - -namespace Mangle { -namespace Sound { - -/// A sample source that decodes files using Audiere -class AudiereSource : public SampleReader -{ - audiere::SampleSourcePtr sample; - - size_t readSamples(void *data, size_t length) - { return sample->read(length, data); } - - void doSetup(); - - public: - /// Decode the given sound file - AudiereSource(const std::string &file); - - /// Decode the given sound stream - AudiereSource(Mangle::Stream::StreamPtr src); - - /// Read directly from an existing audiere::SampleSource - AudiereSource(audiere::SampleSourcePtr src); - - void getInfo(int32_t *rate, int32_t *channels, int32_t *bits); - - void seek(size_t pos) { sample->setPosition(pos/frameSize); } - size_t tell() const { return sample->getPosition()*frameSize; } - size_t size() const { return sample->getLength()*frameSize; } -}; - -#include "loadertemplate.hpp" - -/// A factory that loads AudiereSources from file and stream -typedef SSL_Template AudiereLoader; - -}} // Namespace -#endif diff --git a/libs/mangle/sound/sources/ffmpeg_source.cpp b/libs/mangle/sound/sources/ffmpeg_source.cpp deleted file mode 100644 index 6349be691..000000000 --- a/libs/mangle/sound/sources/ffmpeg_source.cpp +++ /dev/null @@ -1,189 +0,0 @@ -#include "ffmpeg_source.hpp" - -#include - -using namespace Mangle::Sound; - -// Static output buffer. Not thread safe, but supports multiple -// streams operated from the same thread. -static uint8_t outBuf[AVCODEC_MAX_AUDIO_FRAME_SIZE]; - -static void fail(const std::string &msg) -{ throw std::runtime_error("FFMpeg exception: " + msg); } - -// --- Loader --- - -static bool init = false; - -FFMpegLoader::FFMpegLoader(bool setup) -{ - if(setup && !init) - { - av_register_all(); - av_log_set_level(AV_LOG_ERROR); - init = true; - } -} - -// --- Source --- - -FFMpegSource::FFMpegSource(const std::string &file) -{ - std::string msg; - AVCodec *codec; - - if(av_open_input_file(&FmtCtx, file.c_str(), NULL, 0, NULL) != 0) - fail("Error loading audio file " + file); - - if(av_find_stream_info(FmtCtx) < 0) - { - msg = "Error in file stream " + file; - goto err; - } - - // Pick the first audio stream, if any - for(StreamNum = 0; StreamNum < FmtCtx->nb_streams; StreamNum++) - { - // Pick the first audio stream - if(FmtCtx->streams[StreamNum]->codec->codec_type == CODEC_TYPE_AUDIO) - break; - } - - if(StreamNum == FmtCtx->nb_streams) - fail("File '" + file + "' didn't contain any audio streams"); - - // Open the decoder - CodecCtx = FmtCtx->streams[StreamNum]->codec; - codec = avcodec_find_decoder(CodecCtx->codec_id); - - if(!codec || avcodec_open(CodecCtx, codec) < 0) - { - msg = "Error loading '" + file + "': "; - if(codec) - msg += "coded error"; - else - msg += "no codec found"; - goto err; - } - - // No errors, we're done - return; - - // Handle errors - err: - av_close_input_file(FmtCtx); - fail(msg); -} - -FFMpegSource::~FFMpegSource() -{ - avcodec_close(CodecCtx); - av_close_input_file(FmtCtx); -} - -void FFMpegSource::getInfo(int32_t *rate, int32_t *channels, int32_t *bits) -{ - if(rate) *rate = CodecCtx->sample_rate; - if(channels) *channels = CodecCtx->channels; - if(bits) *bits = 16; -} - -size_t FFMpegSource::read(void *data, size_t length) -{ - if(isEof) return 0; - - size_t left = length; - uint8_t *outPtr = (uint8_t*)data; - - // First, copy over any stored data we might be sitting on - { - size_t s = storage.size(); - size_t copy = s; - if(s) - { - // Make sure there's room - if(copy > left) - copy = left; - - // Copy - memcpy(outPtr, &storage[0], copy); - outPtr += copy; - left -= copy; - - // Is there anything left in the storage? - assert(s>= copy); - s -= copy; - if(s) - { - assert(left == 0); - - // Move it to the start and resize - memmove(&storage[0], &storage[copy], s); - storage.resize(s); - } - } - } - - // Next, get more input data from stream, and decode it - while(left) - { - AVPacket packet; - - // Get the next packet, if any - if(av_read_frame(FmtCtx, &packet) < 0) - break; - - // We only allow one stream per file at the moment - assert((int)StreamNum == packet.stream_index); - - // Decode the packet - int len = AVCODEC_MAX_AUDIO_FRAME_SIZE; - int tmp = avcodec_decode_audio2(CodecCtx, (int16_t*)outBuf, - &len, packet.data, packet.size); - assert(tmp < 0 || tmp == packet.size); - - // We don't need the input packet any longer - av_free_packet(&packet); - - if(tmp < 0) - fail("Error decoding audio stream"); - - // Copy whatever data we got, and advance the pointer - if(len > 0) - { - // copy = how many bytes do we copy now - size_t copy = len; - if(copy > left) - copy = left; - - // len = how many bytes are left uncopied - len -= copy; - - // copy data - memcpy(outPtr, outBuf, copy); - - // left = how much space is left in the caller output - // buffer. This loop repeats as long left is > 0 - left -= copy; - outPtr += copy; - assert(left >= 0); - - if(len > 0) - { - // There were uncopied bytes. Store them for later. - assert(left == 0); - storage.resize(len); - memcpy(&storage[0], outBuf, len); - } - } - } - - // End of loop. Return the number of bytes copied. - assert(left <= length); - - // If we're returning less than asked for, then we're done - if(left > 0) - isEof = true; - - return length - left; -} diff --git a/libs/mangle/sound/sources/ffmpeg_source.hpp b/libs/mangle/sound/sources/ffmpeg_source.hpp deleted file mode 100644 index d422b9809..000000000 --- a/libs/mangle/sound/sources/ffmpeg_source.hpp +++ /dev/null @@ -1,52 +0,0 @@ -#ifndef MANGLE_SOUND_FFMPEG_H -#define MANGLE_SOUND_FFMPEG_H - -#include "../source.hpp" -#include -#include - -extern "C" -{ -#include -#include -} - -namespace Mangle { -namespace Sound { - -class FFMpegSource : public SampleSource -{ - AVFormatContext *FmtCtx; - AVCodecContext *CodecCtx; - unsigned int StreamNum; - - std::vector storage; - - public: - /// Decode the given sound file - FFMpegSource(const std::string &file); - - /// Decode the given sound stream (not supported by FFmpeg) - FFMpegSource(Mangle::Stream::StreamPtr src) { assert(0); } - - ~FFMpegSource(); - - // Overrides - void getInfo(int32_t *rate, int32_t *channels, int32_t *bits); - size_t read(void *data, size_t length); -}; - -#include "loadertemplate.hpp" - -/// A factory that loads FFMpegSources from file -class FFMpegLoader : public SSL_Template -{ - public: - - /// Sets up the libavcodec library. If you want to do your own - /// setup, send a setup=false parameter. - FFMpegLoader(bool setup=true); -}; - -}} // namespaces -#endif diff --git a/libs/mangle/sound/sources/libsndfile.cpp b/libs/mangle/sound/sources/libsndfile.cpp deleted file mode 100644 index b69a2d436..000000000 --- a/libs/mangle/sound/sources/libsndfile.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "libsndfile.hpp" - -#include -#include - -using namespace Mangle::Stream; - -static void fail(const std::string &msg) -{ throw std::runtime_error("Mangle::libsndfile: " + msg); } - -using namespace Mangle::Sound; - -void SndFileSource::getInfo(int32_t *_rate, int32_t *_channels, int32_t *_bits) -{ - *_rate = rate; - *_channels = channels; - *_bits = bits; -} - -size_t SndFileSource::readSamples(void *data, size_t length) -{ - // readf_* reads entire frames, including channels - return sf_readf_short((SNDFILE*)handle, (short*)data, length); -} - -SndFileSource::SndFileSource(const std::string &file) -{ - SF_INFO info; - info.format = 0; - handle = sf_open(file.c_str(), SFM_READ, &info); - if(handle == NULL) - fail("Failed to open " + file); - - // I THINK that using sf_read_short forces the library to convert to - // 16 bits no matter what, but the libsndfile docs aren't exactly - // very clear on this point. - channels = info.channels; - rate = info.samplerate; - bits = 16; - - // 16 bits per sample times number of channels - setup(2*channels); -} - -SndFileSource::~SndFileSource() -{ - sf_close((SNDFILE*)handle); -} diff --git a/libs/mangle/sound/sources/libsndfile.hpp b/libs/mangle/sound/sources/libsndfile.hpp deleted file mode 100644 index 7286cf0fe..000000000 --- a/libs/mangle/sound/sources/libsndfile.hpp +++ /dev/null @@ -1,36 +0,0 @@ -#ifndef MANGLE_SOUND_SNDFILE_SOURCE_H -#define MANGLE_SOUND_SNDFILE_SOURCE_H - -#include "sample_reader.hpp" - -namespace Mangle { -namespace Sound { - -/// A sample source that decodes files using libsndfile. Supports most -/// formats except mp3. -class SndFileSource : public SampleReader -{ - void *handle; - int channels, rate, bits; - - size_t readSamples(void *data, size_t length); - - public: - /// Decode the given sound file - SndFileSource(const std::string &file); - - /// Decode the given sound stream (not supported) - SndFileSource(Mangle::Stream::StreamPtr src) { assert(0); } - - ~SndFileSource(); - - void getInfo(int32_t *rate, int32_t *channels, int32_t *bits); -}; - -#include "loadertemplate.hpp" - -/// A factory that loads SndFileSources from file and stream -typedef SSL_Template SndFileLoader; - -}} // Namespace -#endif diff --git a/libs/mangle/sound/sources/loadertemplate.hpp b/libs/mangle/sound/sources/loadertemplate.hpp deleted file mode 100644 index a27a77d10..000000000 --- a/libs/mangle/sound/sources/loadertemplate.hpp +++ /dev/null @@ -1,28 +0,0 @@ -#ifndef SSL_TEMPL_H -#define SSL_TEMPL_H - -template -class SSL_Template : public SampleSourceLoader -{ - public: - - SSL_Template() - { - canLoadStream = stream; - canLoadFile = file; - } - - SampleSourcePtr load(const std::string &filename) - { - assert(canLoadFile); - return SampleSourcePtr(new SourceT(filename)); - } - - SampleSourcePtr load(Stream::StreamPtr input) - { - assert(canLoadStream); - return SampleSourcePtr(new SourceT(input)); - } -}; - -#endif diff --git a/libs/mangle/sound/sources/mpg123_source.cpp b/libs/mangle/sound/sources/mpg123_source.cpp deleted file mode 100644 index 24d6ecce1..000000000 --- a/libs/mangle/sound/sources/mpg123_source.cpp +++ /dev/null @@ -1,115 +0,0 @@ -#include "mpg123_source.hpp" - -#include - -#include - -using namespace Mangle::Stream; - -/* - TODOs: - - - mpg123 impressively enough supports custom stream reading. Which - means we could (and SHOULD!) support reading from Mangle::Streams - as well. But I'll save it til I need it. - - An alternative way to do this is through feeding (which they also - support), but that's more messy. - - - the library also supports output, via various other sources, - including ALSA, OSS, PortAudio, PulseAudio and SDL. Using this - library as a pure output library (if that is possible) would be a - nice shortcut over using those libraries - OTOH it's another - dependency. - - - we could implement seek(), tell() and size(), but they aren't - really necessary. Furthermore, since the returned size is only a - guess, it is not safe to rely on it. - */ - -static void fail(const std::string &msg) -{ throw std::runtime_error("Mangle::Mpg123 exception: " + msg); } - -static void checkError(int err, void *mh = NULL) -{ - if(err != MPG123_OK) - { - std::string msg; - if(mh) msg = mpg123_strerror((mpg123_handle*)mh); - else msg = mpg123_plain_strerror(err); - fail(msg); - } -} - -using namespace Mangle::Sound; - -void Mpg123Source::getInfo(int32_t *pRate, int32_t *pChannels, int32_t *pBits) -{ - // Use the values we found in the constructor - *pRate = rate; - *pChannels = channels; - *pBits = bits; -} - -size_t Mpg123Source::read(void *data, size_t length) -{ - size_t done; - // This is extraordinarily nice. I like this library. - int err = mpg123_read((mpg123_handle*)mh, (unsigned char*)data, length, &done); - assert(done <= length); - if(err == MPG123_DONE) - isEof = true; - else - checkError(err, mh); - return done; -} - -Mpg123Loader::Mpg123Loader(bool setup) -{ - // Do as we're told - if(setup) - { - int err = mpg123_init(); - checkError(err); - } - didSetup = setup; -} - -Mpg123Loader::~Mpg123Loader() -{ - // Deinitialize the library on exit - if(didSetup) - mpg123_exit(); -} - -Mpg123Source::Mpg123Source(const std::string &file) -{ - int err; - - // Create a new handle - mh = mpg123_new(NULL, &err); - if(mh == NULL) - checkError(err, mh); - - mpg123_handle *mhh = (mpg123_handle*)mh; - - // Open the file (hack around constness) - err = mpg123_open(mhh, (char*)file.c_str()); - checkError(err, mh); - - // Get the format - int encoding; - err = mpg123_getformat(mhh, &rate, &channels, &encoding); - checkError(err, mh); - if(encoding != MPG123_ENC_SIGNED_16) - fail("Unsupported encoding in " + file); - - // This is the only bit size we support. - bits = 16; -} - -Mpg123Source::~Mpg123Source() -{ - mpg123_close((mpg123_handle*)mh); - mpg123_delete((mpg123_handle*)mh); -} diff --git a/libs/mangle/sound/sources/mpg123_source.hpp b/libs/mangle/sound/sources/mpg123_source.hpp deleted file mode 100644 index 1ac16b530..000000000 --- a/libs/mangle/sound/sources/mpg123_source.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef MANGLE_SOUND_MPG123_SOURCE_H -#define MANGLE_SOUND_MPG123_SOURCE_H - -#include "../source.hpp" -#include - -namespace Mangle { -namespace Sound { - -/// A sample source that decodes files using libmpg123. Only supports -/// MP3 files. -class Mpg123Source : public SampleSource -{ - void *mh; - long int rate; - int channels, bits; - - public: - /// Decode the given sound file - Mpg123Source(const std::string &file); - - /// Needed by SSL_Template but not yet supported - Mpg123Source(Mangle::Stream::StreamPtr data) - { assert(0); } - - ~Mpg123Source(); - - void getInfo(int32_t *rate, int32_t *channels, int32_t *bits); - size_t read(void *data, size_t length); -}; - -#include "loadertemplate.hpp" - -/// A factory that loads Mpg123Sources from file and stream -struct Mpg123Loader : SSL_Template -{ - /** Sets up libmpg123 for you, and closes it on destruction. If you - want to do this yourself, send setup=false. - */ - Mpg123Loader(bool setup=true); - ~Mpg123Loader(); -private: - bool didSetup; -}; - -}} // Namespace -#endif diff --git a/libs/mangle/sound/sources/sample_reader.cpp b/libs/mangle/sound/sources/sample_reader.cpp deleted file mode 100644 index c30de654a..000000000 --- a/libs/mangle/sound/sources/sample_reader.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "sample_reader.hpp" - -#include - -using namespace Mangle::Sound; - -void SampleReader::setup(int size) -{ - pullSize = 0; - frameSize = size; - pullOver = new char[size]; -} - -SampleReader::~SampleReader() -{ - if(pullOver) - delete[] pullOver; -} - -size_t SampleReader::read(void *_data, size_t length) -{ - if(isEof) return 0; - char *data = (char*)_data; - - // Pullsize holds the number of bytes that were copied "extra" at - // the end of LAST round. If non-zero, it also means there is data - // left in the pullOver buffer. - if(pullSize) - { - // Amount of data left - size_t doRead = frameSize - pullSize; - assert(doRead > 0); - - // Make sure we don't read more than we're supposed to - if(doRead > length) doRead = length; - - memcpy(data, pullOver+pullSize, doRead); - - // Update the number of bytes now copied - pullSize += doRead; - assert(pullSize <= frameSize); - - if(pullSize < frameSize) - { - // There is STILL data left in the pull buffer, and we've - // done everything we were supposed to. Leave it and return. - assert(doRead == length); - return doRead; - } - - // Set up variables for further reading below. No need to update - // pullSize, it is overwritten anyway. - length -= doRead; - data += doRead; - } - - // Number of whole frames - size_t frames = length / frameSize; - - // Read the data - size_t res = readSamples(data, frames); - assert(res <= frames); - - // Total bytes read - size_t num = res*frameSize; - data += num; - - if(res < frames) - { - // End of stream. - isEof = true; - // Determine how much we read - return data-(char*)_data; - } - - // Determine the overshoot - pullSize = length - num; - assert(pullSize < frameSize && pullSize >= 0); - - // Are we missing data? - if(pullSize) - { - // Fill in one sample - res = readSamples(pullOver,1); - assert(res == 1 || res == 0); - if(res) - { - // Move as much as we can into the output buffer - memcpy(data, pullOver, pullSize); - data += pullSize; - } - else - // Failed reading, we're out of data - isEof = true; - } - - // Return the total number of bytes stored - return data-(char*)_data; -} diff --git a/libs/mangle/sound/sources/sample_reader.hpp b/libs/mangle/sound/sources/sample_reader.hpp deleted file mode 100644 index 89ddf1f65..000000000 --- a/libs/mangle/sound/sources/sample_reader.hpp +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef MANGLE_SOUND_SAMPLE_READER_H -#define MANGLE_SOUND_SAMPLE_READER_H - -#include "../source.hpp" - -namespace Mangle { -namespace Sound { - - /* This is a helper base class for other SampleSource - implementations. Certain sources (like Audiere and libsndfile) - insist on reading whole samples rather than bytes. This class - compensates for that, and allows you to read bytes rather than - samples. - - There are two ways for subclasses to use this class. EITHER call - setup() with the size of frameSize. This will allocate a buffer, - which the destructor frees. OR set frameSize manually and - manipulate the pullOver pointer yourself. In that case you MUST - reset it to NULL if you don't want the destructor to call - delete[] on it. - */ -class SampleReader : public SampleSource -{ - // How much of the above buffer is in use. - int pullSize; - -protected: - // Pullover buffer - char* pullOver; - - // Size of one frame, in bytes. This is also the size of the - // pullOver buffer. - int frameSize; - - // The parameter gives the size of one sample/frame, in bytes. - void setup(int); - - // Read the given number of samples, in multiples of frameSize. Does - // not have to set or respect isEof. - virtual size_t readSamples(void *data, size_t num) = 0; - - public: - SampleReader() : pullSize(0), pullOver(NULL) {} - ~SampleReader(); - size_t read(void *data, size_t length); -}; -}} // Namespace -#endif diff --git a/libs/mangle/sound/sources/stream_source.hpp b/libs/mangle/sound/sources/stream_source.hpp deleted file mode 100644 index 43c605a00..000000000 --- a/libs/mangle/sound/sources/stream_source.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#ifndef MANGLE_SOUND_STREAMSOURCE_H -#define MANGLE_SOUND_STREAMSOURCE_H - -#include "../source.hpp" - -namespace Mangle { -namespace Sound { - -/// A class for reading raw samples directly from a stream. -class Stream2Samples : public SampleSource -{ - Mangle::Stream::StreamPtr inp; - int32_t rate, channels, bits; - - public: - Stream2Samples(Mangle::Stream::StreamPtr _inp, int32_t _rate, int32_t _channels, int32_t _bits) - : inp(_inp), rate(_rate), channels(_channels), bits(_bits) - { - isSeekable = inp->isSeekable; - hasPosition = inp->hasPosition; - hasSize = inp->hasSize; - hasPtr = inp->hasPtr; - } - - /// Get the sample rate, number of channels, and bits per - /// sample. NULL parameters are ignored. - void getInfo(int32_t *_rate, int32_t *_channels, int32_t *_bits) - { - if(_rate) *_rate = rate; - if(_channels) *_channels = channels; - if(_bits) *_bits = bits; - } - - size_t read(void *out, size_t count) - { return inp->read(out, count); } - - void seek(size_t pos) { inp->seek(pos); } - size_t tell() const { return inp->tell(); } - size_t size() const { return inp->size(); } - bool eof() const { return inp->eof(); } - const void *getPtr() { return inp->getPtr(); } - const void *getPtr(size_t size) { return inp->getPtr(size); } - const void *getPtr(size_t pos, size_t size) { return inp->getPtr(pos, size); } -}; - -}} // namespaces -#endif diff --git a/libs/mangle/sound/sources/wav_source.cpp b/libs/mangle/sound/sources/wav_source.cpp deleted file mode 100644 index a46b3d27e..000000000 --- a/libs/mangle/sound/sources/wav_source.cpp +++ /dev/null @@ -1,99 +0,0 @@ -#include "wav_source.hpp" - -#include "../../stream/servers/file_stream.hpp" - -#include - -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -static void fail(const std::string &msg) -{ throw std::runtime_error("Mangle::Wav exception: " + msg); } - -void WavSource::getInfo(int32_t *pRate, int32_t *pChannels, int32_t *pBits) -{ - // Use the values we found in the constructor - *pRate = rate; - *pChannels = channels; - *pBits = bits; -} - -void WavSource::seek(size_t pos) -{ - // Seek the stream and set 'left' - assert(isSeekable); - if(pos > total) pos = total; - input->seek(dataOffset + pos); - left = total-pos; -} - -size_t WavSource::read(void *data, size_t length) -{ - if(length > left) - length = left; - size_t read = input->read(data, length); - if(read < length) - // Something went wrong - fail("WAV read error"); - return length; -} - -void WavSource::open(Mangle::Stream::StreamPtr data) -{ - input = data; - - hasPosition = true; - hasSize = true; - // If we can check position and seek in the input stream, then we - // can seek the wav data too. - isSeekable = input->isSeekable && input->hasPosition; - - // Read header - unsigned int val; - - input->read(&val,4); // header - if(val != 0x46464952) // "RIFF" - fail("Not a WAV file"); - - input->read(&val,4); // size (ignored) - input->read(&val,4); // file format - if(val != 0x45564157) // "WAVE" - fail("Not a valid WAV file"); - - input->read(&val,4); // "fmt " - input->read(&val,4); // chunk size (must be 16) - if(val != 16) - fail("Unsupported WAV format"); - - input->read(&val,2); - if(val != 1) - fail("Non-PCM (compressed) WAV files not supported"); - - // Sound data specification - channels = 0; - input->read(&channels,2); - input->read(&rate, 4); - - // Skip next 6 bytes - input->read(&val, 4); - input->read(&val, 2); - - // Bits per sample - bits = 0; - input->read(&bits,2); - - input->read(&val,4); // Data header - if(val != 0x61746164) // "data" - fail("Expected data block"); - - // Finally, read the data size - input->read(&total,4); - left = total; - - // Store the beginning of the data block for later - if(input->hasPosition) - dataOffset = input->tell(); -} - -WavSource::WavSource(const std::string &file) -{ open(StreamPtr(new FileStream(file))); } diff --git a/libs/mangle/sound/sources/wav_source.hpp b/libs/mangle/sound/sources/wav_source.hpp deleted file mode 100644 index 227f4da73..000000000 --- a/libs/mangle/sound/sources/wav_source.hpp +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef MANGLE_SOUND_WAV_SOURCE_H -#define MANGLE_SOUND_WAV_SOURCE_H - -#include "../source.hpp" -#include - -namespace Mangle { -namespace Sound { - -/// WAV file decoder. Has no external library dependencies. -class WavSource : public SampleSource -{ - // Sound info - uint32_t rate, channels, bits; - - // Total size (of output) and bytes left - uint32_t total, left; - - // Offset in input of the beginning of the data block - size_t dataOffset; - - Mangle::Stream::StreamPtr input; - - void open(Mangle::Stream::StreamPtr); - - public: - /// Decode the given sound file - WavSource(const std::string&); - - /// Decode from stream - WavSource(Mangle::Stream::StreamPtr s) - { open(s); } - - void getInfo(int32_t *rate, int32_t *channels, int32_t *bits); - size_t read(void *data, size_t length); - - void seek(size_t); - size_t tell() const { return total-left; } - size_t size() const { return total; } - bool eof() const { return left > 0; } -}; - -#include "loadertemplate.hpp" - -/// A factory that loads WavSources from file and stream -typedef SSL_Template WavLoader; - -}} // Namespace -#endif diff --git a/libs/mangle/sound/tests/.gitignore b/libs/mangle/sound/tests/.gitignore deleted file mode 100644 index 814490404..000000000 --- a/libs/mangle/sound/tests/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*_test diff --git a/libs/mangle/sound/tests/Makefile b/libs/mangle/sound/tests/Makefile deleted file mode 100644 index 6fcac72da..000000000 --- a/libs/mangle/sound/tests/Makefile +++ /dev/null @@ -1,38 +0,0 @@ -GCC=g++ -I../ -Wall - -all: audiere_source_test ffmpeg_source_test openal_output_test openal_audiere_test openal_ffmpeg_test openal_mpg123_test openal_sndfile_test wav_source_test openal_various_test - -L_FFMPEG=$(shell pkg-config --libs libavcodec libavformat) -I_FFMPEG=-I/usr/include/libavcodec -I/usr/include/libavformat -L_OPENAL=$(shell pkg-config --libs openal) -L_AUDIERE=-laudiere - -wav_source_test: wav_source_test.cpp ../sources/wav_source.cpp - $(GCC) $^ -o $@ - -openal_various_test: openal_various_test.cpp ../sources/mpg123_source.cpp ../sources/wav_source.cpp ../outputs/openal_out.cpp - $(GCC) $^ -o $@ -lmpg123 ${L_OPENAL} - -openal_audiere_test: openal_audiere_test.cpp ../sources/audiere_source.cpp ../sources/sample_reader.cpp ../outputs/openal_out.cpp ../../stream/clients/audiere_file.cpp - $(GCC) $^ -o $@ $(L_AUDIERE) $(L_OPENAL) - -openal_ffmpeg_test: openal_ffmpeg_test.cpp ../sources/ffmpeg_source.cpp ../outputs/openal_out.cpp - $(GCC) $^ -o $@ $(L_FFMPEG) $(L_OPENAL) $(I_FFMPEG) - -openal_mpg123_test: openal_mpg123_test.cpp ../sources/mpg123_source.cpp ../outputs/openal_out.cpp - $(GCC) $^ -o $@ -lmpg123 ${L_OPENAL} - -openal_sndfile_test: openal_sndfile_test.cpp ../sources/libsndfile.cpp ../sources/sample_reader.cpp ../outputs/openal_out.cpp - $(GCC) $^ -o $@ -lsndfile ${L_OPENAL} - -openal_output_test: openal_output_test.cpp ../outputs/openal_out.cpp - $(GCC) $^ -o $@ $(L_OPENAL) - -audiere_source_test: audiere_source_test.cpp ../sources/audiere_source.cpp ../../stream/clients/audiere_file.cpp ../sources/sample_reader.cpp - $(GCC) $^ -o $@ $(L_AUDIERE) - -ffmpeg_source_test: ffmpeg_source_test.cpp ../sources/ffmpeg_source.cpp - $(GCC) $^ -o $@ $(L_FFMPEG) $(I_FFMPEG) - -clean: - rm *_test diff --git a/libs/mangle/sound/tests/audiere_source_test.cpp b/libs/mangle/sound/tests/audiere_source_test.cpp deleted file mode 100644 index 637d743b2..000000000 --- a/libs/mangle/sound/tests/audiere_source_test.cpp +++ /dev/null @@ -1,68 +0,0 @@ -#include - -#include "../../stream/servers/file_stream.hpp" -#include "../sources/audiere_source.hpp" - -#include -#include - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -// Contents and size of cow.raw -void *orig; -size_t orig_size; - -void run(SampleSourcePtr &src) -{ - size_t ss = src->size(); - assert(ss == orig_size); - - cout << "Source size: " << ss << endl; - int rate, channels, bits; - src->getInfo(&rate, &channels, &bits); - cout << "rate=" << rate << "\nchannels=" << channels - << "\nbits=" << bits << endl; - - cout << "Reading entire buffer into memory\n"; - void *buf = malloc(ss); - src->read(buf, ss); - - cout << "Comparing...\n"; - if(memcmp(buf, orig, ss) != 0) - { - cout << "Oops!\n"; - assert(0); - } - - cout << "Done\n"; -} - -int main() -{ - { - cout << "Reading cow.raw first\n"; - FileStream tmp("cow.raw"); - orig_size = tmp.size(); - cout << "Size: " << orig_size << endl; - orig = malloc(orig_size); - tmp.read(orig, orig_size); - cout << "Done\n"; - } - - { - cout << "\nLoading cow.wav by filename:\n"; - SampleSourcePtr cow_file( new AudiereSource("cow.wav") ); - run(cow_file); - } - - { - cout << "\nLoading cow.wav by stream:\n"; - StreamPtr inp( new FileStream("cow.wav") ); - SampleSourcePtr cow_stream( new AudiereSource(inp) ); - run(cow_stream); - } - - return 0; -} diff --git a/libs/mangle/sound/tests/cow.raw b/libs/mangle/sound/tests/cow.raw deleted file mode 100644 index c4d155bbf..000000000 Binary files a/libs/mangle/sound/tests/cow.raw and /dev/null differ diff --git a/libs/mangle/sound/tests/cow.wav b/libs/mangle/sound/tests/cow.wav deleted file mode 100644 index 494e6c4ac..000000000 Binary files a/libs/mangle/sound/tests/cow.wav and /dev/null differ diff --git a/libs/mangle/sound/tests/ffmpeg_source_test.cpp b/libs/mangle/sound/tests/ffmpeg_source_test.cpp deleted file mode 100644 index f03b15b99..000000000 --- a/libs/mangle/sound/tests/ffmpeg_source_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include - -#include "../../stream/servers/file_stream.hpp" -#include "../sources/ffmpeg_source.hpp" - -#include -#include - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -// Contents and size of cow.raw -void *orig; -size_t orig_size; - -void run(SampleSourcePtr &src) -{ - int rate, channels, bits; - src->getInfo(&rate, &channels, &bits); - cout << "rate=" << rate << "\nchannels=" << channels - << "\nbits=" << bits << endl; - - cout << "Reading entire buffer into memory\n"; - void *buf = malloc(orig_size); - size_t ss = src->read(buf, orig_size); - cout << "Actually read: " << ss << endl; - assert(ss == orig_size); - - cout << "Comparing...\n"; - if(memcmp(buf, orig, ss) != 0) - { - cout << "Oops!\n"; - assert(0); - } - - cout << "Done\n"; -} - -int main() -{ - { - cout << "Reading cow.raw first\n"; - FileStream tmp("cow.raw"); - orig_size = tmp.size(); - cout << "Size: " << orig_size << endl; - orig = malloc(orig_size); - tmp.read(orig, orig_size); - cout << "Done\n"; - } - - // Initializes the library, not used for anything else. - FFMpegLoader fm; - - { - cout << "\nLoading cow.wav by filename:\n"; - SampleSourcePtr cow_file( new FFMpegSource("cow.wav") ); - run(cow_file); - } - - return 0; -} diff --git a/libs/mangle/sound/tests/openal_audiere_test.cpp b/libs/mangle/sound/tests/openal_audiere_test.cpp deleted file mode 100644 index ced7fe5d2..000000000 --- a/libs/mangle/sound/tests/openal_audiere_test.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include - -#include "../../stream/servers/file_stream.hpp" -#include "../filters/openal_audiere.hpp" - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -OpenAL_Audiere_Factory mg; - -void play(const char* name, bool stream=false) -{ - // Only load streams if the backend supports it - if(stream && !mg.canLoadStream) - return; - - cout << "Playing " << name; - if(stream) cout << " (from stream)"; - cout << "\n"; - - SoundPtr snd; - - try - { - if(stream) - snd = mg.load(StreamPtr(new FileStream(name))); - else - snd = mg.load(name); - - snd->play(); - - while(snd->isPlaying()) - { - usleep(10000); - if(mg.needsUpdate) mg.update(); - } - } - catch(exception &e) - { - cout << " ERROR: " << e.what() << "\n"; - } -} - -int main() -{ - play("cow.wav"); - play("owl.ogg"); - play("cow.wav", true); - return 0; -} diff --git a/libs/mangle/sound/tests/openal_ffmpeg_test.cpp b/libs/mangle/sound/tests/openal_ffmpeg_test.cpp deleted file mode 100644 index d4b8e9300..000000000 --- a/libs/mangle/sound/tests/openal_ffmpeg_test.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include - -#include "../../stream/servers/file_stream.hpp" -#include "../filters/openal_ffmpeg.hpp" - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -OpenAL_FFMpeg_Factory mg; - -void play(const char* name, bool stream=false) -{ - // Only load streams if the backend supports it - if(stream && !mg.canLoadStream) - return; - - cout << "Playing " << name; - if(stream) cout << " (from stream)"; - cout << "\n"; - - SoundPtr snd; - - try - { - if(stream) - snd = mg.load(StreamPtr(new FileStream(name))); - else - snd = mg.load(name); - - snd->play(); - - while(snd->isPlaying()) - { - usleep(10000); - if(mg.needsUpdate) mg.update(); - } - } - catch(exception &e) - { - cout << " ERROR: " << e.what() << "\n"; - } -} - -int main() -{ - play("cow.wav"); - play("owl.ogg"); - play("cow.wav", true); - return 0; -} diff --git a/libs/mangle/sound/tests/openal_mpg123_test.cpp b/libs/mangle/sound/tests/openal_mpg123_test.cpp deleted file mode 100644 index fef1a5605..000000000 --- a/libs/mangle/sound/tests/openal_mpg123_test.cpp +++ /dev/null @@ -1,54 +0,0 @@ -#include -#include - -#include "../../stream/servers/file_stream.hpp" -#include "../filters/openal_mpg123.hpp" - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -OpenAL_Mpg123_Factory mg; - -void play(const char* name, bool stream=false) -{ - // Only load streams if the backend supports it - if(stream && !mg.canLoadStream) - return; - - cout << "Playing " << name; - if(stream) cout << " (from stream)"; - cout << "\n"; - - SoundPtr snd; - - try - { - if(stream) - snd = mg.load(StreamPtr(new FileStream(name))); - else - snd = mg.load(name); - - snd->setStreaming(true); - snd->play(); - - while(snd->isPlaying()) - { - usleep(10000); - if(mg.needsUpdate) mg.update(); - } - } - catch(exception &e) - { - cout << " ERROR: " << e.what() << "\n"; - } -} - -int main(int argc, char**argv) -{ - if(argc != 2) - cout << "Please specify an MP3 file\n"; - else - play(argv[1]); - return 0; -} diff --git a/libs/mangle/sound/tests/openal_output_test.cpp b/libs/mangle/sound/tests/openal_output_test.cpp deleted file mode 100644 index a8059ec65..000000000 --- a/libs/mangle/sound/tests/openal_output_test.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include -#include - -#include "../../stream/servers/file_stream.hpp" -#include "../sources/stream_source.hpp" -#include "../outputs/openal_out.hpp" - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -int main() -{ - cout << "Loading cow.raw\n"; - - int rate = 11025; - int chan = 1; - int bits = 16; - - cout << " rate=" << rate << "\n channels=" << chan - << "\n bits=" << bits << endl; - - StreamPtr file( new FileStream("cow.raw") ); - SampleSourcePtr source( new Stream2Samples( file, rate, chan, bits)); - - cout << "Playing\n"; - - OpenAL_Factory mg; - - SoundPtr snd = mg.loadRaw(source); - - try - { - // Try setting all kinds of stuff before playing. OpenAL_Sound - // uses delayed buffer loading, but these should still work - // without a buffer. - snd->stop(); - snd->pause(); - snd->setVolume(0.8); - snd->setPitch(0.9); - - // Also test streaming, since all the other examples test - // non-streaming sounds. - snd->setStreaming(true); - - snd->play(); - - while(snd->isPlaying()) - { - usleep(10000); - mg.update(); - } - } - catch(exception &e) - { - cout << " ERROR: " << e.what() << "\n"; - } - return 0; -} diff --git a/libs/mangle/sound/tests/openal_sndfile_test.cpp b/libs/mangle/sound/tests/openal_sndfile_test.cpp deleted file mode 100644 index bd5f117a5..000000000 --- a/libs/mangle/sound/tests/openal_sndfile_test.cpp +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include - -#include "../../stream/servers/file_stream.hpp" -#include "../filters/openal_sndfile.hpp" - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -OpenAL_SndFile_Factory mg; - -void play(const char* name, bool stream=false) -{ - // Only load streams if the backend supports it - if(stream && !mg.canLoadStream) - return; - - cout << "Playing " << name; - if(stream) cout << " (from stream)"; - cout << "\n"; - - SoundPtr snd; - - try - { - if(stream) - snd = mg.load(StreamPtr(new FileStream(name))); - else - snd = mg.load(name); - - snd->play(); - - while(snd->isPlaying()) - { - usleep(10000); - if(mg.needsUpdate) mg.update(); - } - } - catch(exception &e) - { - cout << " ERROR: " << e.what() << "\n"; - } -} - -int main() -{ - play("cow.wav"); - play("owl.ogg"); - play("cow.wav", true); - return 0; -} diff --git a/libs/mangle/sound/tests/openal_various_test.cpp b/libs/mangle/sound/tests/openal_various_test.cpp deleted file mode 100644 index 9426a672e..000000000 --- a/libs/mangle/sound/tests/openal_various_test.cpp +++ /dev/null @@ -1,51 +0,0 @@ -#include -#include - -#include "../../stream/servers/file_stream.hpp" -#include "../filters/openal_various.hpp" - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; - -OpenAL_Various_Factory mg; - -void play(const char* name, bool stream=false) -{ - // Only load streams if the backend supports it - if(stream && !mg.canLoadStream) - return; - - cout << "Playing " << name; - if(stream) cout << " (from stream)"; - cout << "\n"; - - SoundPtr snd; - - try - { - if(stream) - snd = mg.load(StreamPtr(new FileStream(name))); - else - snd = mg.load(name); - - snd->play(); - - while(snd->isPlaying()) - { - usleep(10000); - if(mg.needsUpdate) mg.update(); - } - } - catch(exception &e) - { - cout << " ERROR: " << e.what() << "\n"; - } -} - -int main() -{ - play("cow.wav"); - play("cow.wav", true); - return 0; -} diff --git a/libs/mangle/sound/tests/output/audiere_source_test.out b/libs/mangle/sound/tests/output/audiere_source_test.out deleted file mode 100644 index 47a5a9e41..000000000 --- a/libs/mangle/sound/tests/output/audiere_source_test.out +++ /dev/null @@ -1,21 +0,0 @@ -Reading cow.raw first -Size: 37502 -Done - -Loading cow.wav by filename: -Source size: 37502 -rate=11025 -channels=1 -bits=16 -Reading entire buffer into memory -Comparing... -Done - -Loading cow.wav by stream: -Source size: 37502 -rate=11025 -channels=1 -bits=16 -Reading entire buffer into memory -Comparing... -Done diff --git a/libs/mangle/sound/tests/output/ffmpeg_source_test.out b/libs/mangle/sound/tests/output/ffmpeg_source_test.out deleted file mode 100644 index 1c7d49113..000000000 --- a/libs/mangle/sound/tests/output/ffmpeg_source_test.out +++ /dev/null @@ -1,12 +0,0 @@ -Reading cow.raw first -Size: 37502 -Done - -Loading cow.wav by filename: -rate=11025 -channels=1 -bits=16 -Reading entire buffer into memory -Actually read: 37502 -Comparing... -Done diff --git a/libs/mangle/sound/tests/output/openal_audiere_test.out b/libs/mangle/sound/tests/output/openal_audiere_test.out deleted file mode 100644 index 4fe01eac2..000000000 --- a/libs/mangle/sound/tests/output/openal_audiere_test.out +++ /dev/null @@ -1,3 +0,0 @@ -Playing cow.wav -Playing owl.ogg -Playing cow.wav (from stream) diff --git a/libs/mangle/sound/tests/output/openal_ffmpeg_test.out b/libs/mangle/sound/tests/output/openal_ffmpeg_test.out deleted file mode 100644 index 96e1db0f9..000000000 --- a/libs/mangle/sound/tests/output/openal_ffmpeg_test.out +++ /dev/null @@ -1,2 +0,0 @@ -Playing cow.wav -Playing owl.ogg diff --git a/libs/mangle/sound/tests/output/openal_mpg123_test.out b/libs/mangle/sound/tests/output/openal_mpg123_test.out deleted file mode 100644 index e55dabbb1..000000000 --- a/libs/mangle/sound/tests/output/openal_mpg123_test.out +++ /dev/null @@ -1 +0,0 @@ -Please specify an MP3 file diff --git a/libs/mangle/sound/tests/output/openal_output_test.out b/libs/mangle/sound/tests/output/openal_output_test.out deleted file mode 100644 index 04392a72e..000000000 --- a/libs/mangle/sound/tests/output/openal_output_test.out +++ /dev/null @@ -1,5 +0,0 @@ -Loading cow.raw - rate=11025 - channels=1 - bits=16 -Playing diff --git a/libs/mangle/sound/tests/output/openal_sndfile_test.out b/libs/mangle/sound/tests/output/openal_sndfile_test.out deleted file mode 100644 index 96e1db0f9..000000000 --- a/libs/mangle/sound/tests/output/openal_sndfile_test.out +++ /dev/null @@ -1,2 +0,0 @@ -Playing cow.wav -Playing owl.ogg diff --git a/libs/mangle/sound/tests/output/openal_various_test.out b/libs/mangle/sound/tests/output/openal_various_test.out deleted file mode 100644 index f25a55513..000000000 --- a/libs/mangle/sound/tests/output/openal_various_test.out +++ /dev/null @@ -1 +0,0 @@ -Playing cow.wav diff --git a/libs/mangle/sound/tests/output/wav_source_test.out b/libs/mangle/sound/tests/output/wav_source_test.out deleted file mode 100644 index b6fc8e6fc..000000000 --- a/libs/mangle/sound/tests/output/wav_source_test.out +++ /dev/null @@ -1,12 +0,0 @@ -Source size: 37502 -rate=11025 -channels=1 -bits=16 -Reading entire buffer into memory - -Reading cow.raw -Size: 37502 - -Comparing... - -Done diff --git a/libs/mangle/sound/tests/owl.ogg b/libs/mangle/sound/tests/owl.ogg deleted file mode 100644 index e992f24d4..000000000 Binary files a/libs/mangle/sound/tests/owl.ogg and /dev/null differ diff --git a/libs/mangle/sound/tests/test.sh b/libs/mangle/sound/tests/test.sh deleted file mode 100755 index 2d07708ad..000000000 --- a/libs/mangle/sound/tests/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -make || exit - -mkdir -p output - -PROGS=*_test - -for a in $PROGS; do - if [ -f "output/$a.out" ]; then - echo "Running $a:" - ./$a | diff output/$a.out - - else - echo "Creating $a.out" - ./$a > "output/$a.out" - git add "output/$a.out" - fi -done diff --git a/libs/mangle/sound/tests/wav_source_test.cpp b/libs/mangle/sound/tests/wav_source_test.cpp deleted file mode 100644 index 749af1849..000000000 --- a/libs/mangle/sound/tests/wav_source_test.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include - -#include "../sources/wav_source.hpp" -#include "../../stream/servers/file_stream.hpp" - -#include -#include - -using namespace std; -using namespace Mangle::Sound; -using namespace Mangle::Stream; - -int main() -{ - WavSource wav("cow.wav"); - - cout << "Source size: " << wav.size() << endl; - int rate, channels, bits; - wav.getInfo(&rate, &channels, &bits); - cout << "rate=" << rate << "\nchannels=" << channels - << "\nbits=" << bits << endl; - - cout << "Reading entire buffer into memory\n"; - void *buf = malloc(wav.size()); - wav.read(buf, wav.size()); - - cout << "\nReading cow.raw\n"; - FileStream tmp("cow.raw"); - cout << "Size: " << tmp.size() << endl; - void *buf2 = malloc(tmp.size()); - tmp.read(buf2, tmp.size()); - - cout << "\nComparing...\n"; - if(tmp.size() != wav.size()) - { - cout << "SIZE MISMATCH!\n"; - assert(0); - } - - if(memcmp(buf, buf2, wav.size()) != 0) - { - cout << "CONTENT MISMATCH!\n"; - assert(0); - } - - cout << "\nDone\n"; - return 0; -} diff --git a/libs/openengine/gui/layout.hpp b/libs/openengine/gui/layout.hpp index 3c03423c3..e73b2d1ce 100644 --- a/libs/openengine/gui/layout.hpp +++ b/libs/openengine/gui/layout.hpp @@ -80,6 +80,29 @@ namespace GUI mMainWidget->setCoord(x,y,w,h); } + void adjustWindowCaption() + { + // adjust the size of the window caption so that all text is visible + // NOTE: this assumes that mMainWidget is of type Window. + MyGUI::TextBox* box = static_cast(mMainWidget)->getCaptionWidget(); + box->setSize(box->getTextSize().width + 48, box->getSize().height); + + // in order to trigger alignment updates, we need to update the parent + // mygui doesn't provide a proper way of doing this, so we are just changing size + box->getParent()->setCoord(MyGUI::IntCoord( + box->getParent()->getCoord().left, + box->getParent()->getCoord().top, + box->getParent()->getCoord().width, + box->getParent()->getCoord().height+1 + )); + box->getParent()->setCoord(MyGUI::IntCoord( + box->getParent()->getCoord().left, + box->getParent()->getCoord().top, + box->getParent()->getCoord().width, + box->getParent()->getCoord().height-1 + )); + } + void setVisible(bool b) { mMainWidget->setVisible(b); diff --git a/libs/openengine/sound/sndmanager.cpp b/libs/openengine/sound/sndmanager.cpp deleted file mode 100644 index 02c6ba1e7..000000000 --- a/libs/openengine/sound/sndmanager.cpp +++ /dev/null @@ -1,219 +0,0 @@ -#include "sndmanager.hpp" - -#include "../misc/list.hpp" -#include - -using namespace OEngine::Sound; -using namespace Mangle::Sound; - -/** This is our own internal implementation of the - Mangle::Sound::Sound interface. This class links a SoundPtr to - itself and prevents itself from being deleted as long as the sound - is playing. - */ -struct OEngine::Sound::ManagedSound : SoundFilter -{ -private: - /** Who's your daddy? This is set if and only if we are listed - internally in the given SoundManager. - - It may be NULL if the manager has been deleted but the user - keeps their own SoundPtrs to the object. - */ - SoundManager *mgr; - - /** Keep a weak pointer to ourselves, which we convert into a - 'strong' pointer when we are playing. When 'self' is pointing to - ourselves, the object will never be deleted. - - This is used to make sure the sound is not deleted while - playing, unless it is explicitly ordered to do so by the - manager. - - TODO: This kind of construct is useful. If we need it elsewhere - later, template it. It would be generally useful in any system - where we poll to check if a resource is still needed, but where - manual references are allowed. - */ - WSoundPtr weak; - SoundPtr self; - - // Keep this object from being deleted - void lock() - { - self = SoundPtr(weak); - } - - // Release the lock. This may or may not delete the object. Never do - // anything after calling unlock()! - void unlock() - { - self.reset(); - } - -public: - // Used for putting ourselves in linked lists - ManagedSound *next, *prev; - - /** Detach this sound from its manager. This means that the manager - will no longer know we exist. Typically only called when either - the sound or the manager is about to get deleted. - - Since this means update() will no longer be called, we also have - to unlock the sound manually since it will no longer be able to - do that itself. This means that the sound may be deleted, even - if it is still playing, when the manager is deleted. - - However, you are still allowed to keep and manage your own - SoundPtr references, but the lock/unlock system is disabled - after the manager is gone. - */ - void detach() - { - if(mgr) - { - mgr->detach(this); - mgr = NULL; - } - - // Unlock must be last command. Object may get deleted at this - // point. - unlock(); - } - - ManagedSound(SoundPtr snd, SoundManager *mg) - : SoundFilter(snd), mgr(mg) - {} - ~ManagedSound() { detach(); } - - // Needed to set up the weak pointer - void setup(SoundPtr self) - { - weak = WSoundPtr(self); - } - - // Override play() to mark the object as locked - void play() - { - SoundFilter::play(); - - // Lock the object so that it is not deleted while playing. Only - // do this if we have a manager, otherwise the object will never - // get unlocked. - if(mgr) lock(); - } - - // Called regularly by the manager - void update() - { - // If we're no longer playing, don't force object retention. - if(!isPlaying()) - unlock(); - - // unlock() may delete the object, so don't do anything below this - // point. - } - - SoundPtr clone() - { - // Cloning only works when we have a manager. - assert(mgr); - return mgr->wrap(client->clone()); - } -}; - -struct SoundManager::SoundManagerList -{ -private: - // A linked list of ManagedSound objects. - typedef Misc::List SoundList; - SoundList list; - -public: - // Add a new sound to the list - void addNew(ManagedSound* snd) - { - list.insert(snd); - } - - // Remove a sound from the list - void remove(ManagedSound *snd) - { - list.remove(snd); - } - - // Number of sounds in the list - int numSounds() { return list.getNum(); } - - // Update all sounds - void updateAll() - { - ManagedSound *s = list.getHead(); - while(s) - { - ManagedSound *cur = s; - // Propagate first, since update() may delete object - s = s->next; - cur->update(); - } - } - - // Detach and unlock all sounds - void detachAll() - { - ManagedSound *s = list.getHead(); - while(s) - { - ManagedSound *cur = s; - s = s->next; - cur->detach(); - } - } -}; - -SoundManager::SoundManager(SoundFactoryPtr fact) - : FactoryFilter(fact) -{ - needsUpdate = true; - list = new SoundManagerList; -} - -SoundManager::~SoundManager() -{ - // Detach all sounds - list->detachAll(); -} - -SoundPtr SoundManager::wrap(SoundPtr client) -{ - // Create and set up the sound wrapper - ManagedSound *snd = new ManagedSound(client,this); - SoundPtr ptr(snd); - snd->setup(ptr); - - // Add ourselves to the list of all sounds - list->addNew(snd); - - return ptr; -} - -// Remove the sound from this manager. -void SoundManager::detach(ManagedSound *sound) -{ - list->remove(sound); -} - -int SoundManager::numSounds() -{ - return list->numSounds(); -} - -void SoundManager::update() -{ - // Update all the sounds we own - list->updateAll(); - - // Update the source if it needs it - if(client->needsUpdate) - client->update(); -} diff --git a/libs/openengine/sound/sndmanager.hpp b/libs/openengine/sound/sndmanager.hpp deleted file mode 100644 index 5ea0c4fc3..000000000 --- a/libs/openengine/sound/sndmanager.hpp +++ /dev/null @@ -1,93 +0,0 @@ -#ifndef OENGINE_SOUND_MANAGER_H -#define OENGINE_SOUND_MANAGER_H - -#include - -namespace OEngine -{ - namespace Sound - { - using namespace Mangle::Sound; - - class ManagedSound; - - /** A manager of Mangle::Sounds. - - The sound manager is a wrapper around the more low-level - SoundFactory - although it is also itself an implementation of - SoundFactory. It will: - - keep a list of all created sounds - - let you iterate the list - - keep references to playing sounds so you don't have to - - auto-release references to sounds that are finished playing - (ie. deleting them if you're not referencing them) - */ - class SoundManager : public FactoryFilter - { - // Shove the implementation details into the cpp file. - struct SoundManagerList; - SoundManagerList *list; - - // Create a new sound wrapper based on the given source sound. - SoundPtr wrap(SoundPtr snd); - - /** Internal function. Will completely disconnect the given - sound from this manager. Called from ManagedSound. - */ - friend class ManagedSound; - void detach(ManagedSound *sound); - public: - SoundManager(SoundFactoryPtr fact); - ~SoundManager(); - void update(); - - /// Get number of sounds currently managed by this manager. - int numSounds(); - - SoundPtr loadRaw(SampleSourcePtr input) - { return wrap(client->loadRaw(input)); } - - SoundPtr load(Mangle::Stream::StreamPtr input) - { return wrap(client->load(input)); } - - SoundPtr load(const std::string &file) - { return wrap(client->load(file)); } - - // Play a sound immediately, and release when done unless you - // keep the returned SoundPtr. - SoundPtr play(Mangle::Stream::StreamPtr sound) - { - SoundPtr snd = load(sound); - snd->play(); - return snd; - } - - SoundPtr play(const std::string &sound) - { - SoundPtr snd = load(sound); - snd->play(); - return snd; - } - - // Ditto for 3D sounds - SoundPtr play3D(Mangle::Stream::StreamPtr sound, float x, float y, float z) - { - SoundPtr snd = load(sound); - snd->setPos(x,y,z); - snd->play(); - return snd; - } - - SoundPtr play3D(const std::string &sound, float x, float y, float z) - { - SoundPtr snd = load(sound); - snd->setPos(x,y,z); - snd->play(); - return snd; - } - }; - - typedef boost::shared_ptr SoundManagerPtr; - } -} -#endif diff --git a/libs/openengine/sound/tests/Makefile b/libs/openengine/sound/tests/Makefile deleted file mode 100644 index 04952167f..000000000 --- a/libs/openengine/sound/tests/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -GCC=g++ -I../ - -all: sound_manager_test sound_3d_test - -L_FFMPEG=$(shell pkg-config --libs libavcodec libavformat) -L_OPENAL=$(shell pkg-config --libs openal) -L_AUDIERE=-laudiere - -sound_manager_test: sound_manager_test.cpp ../../mangle/sound/sources/audiere_source.cpp ../../mangle/sound/outputs/openal_out.cpp ../../mangle/stream/clients/audiere_file.cpp ../sndmanager.cpp - $(GCC) $^ -o $@ $(L_AUDIERE) $(L_OPENAL) -I../.. - -sound_3d_test: sound_3d_test.cpp ../../mangle/sound/sources/audiere_source.cpp ../../mangle/sound/outputs/openal_out.cpp ../../mangle/stream/clients/audiere_file.cpp ../sndmanager.cpp - $(GCC) $^ -o $@ $(L_AUDIERE) $(L_OPENAL) -I../.. - -clean: - rm *_test diff --git a/libs/openengine/sound/tests/output/sound_3d_test.out b/libs/openengine/sound/tests/output/sound_3d_test.out deleted file mode 100644 index a443c84f0..000000000 --- a/libs/openengine/sound/tests/output/sound_3d_test.out +++ /dev/null @@ -1,3 +0,0 @@ -Playing at 0,0,0 -Playing at 1,1,0 -Playing at -1,0,0 diff --git a/libs/openengine/sound/tests/output/sound_manager_test.out b/libs/openengine/sound/tests/output/sound_manager_test.out deleted file mode 100644 index 2b458493d..000000000 --- a/libs/openengine/sound/tests/output/sound_manager_test.out +++ /dev/null @@ -1,5 +0,0 @@ -Playing ../../mangle/sound/tests/cow.wav -Replaying -pause -restart -Done playing. diff --git a/libs/openengine/sound/tests/sound_3d_test.cpp b/libs/openengine/sound/tests/sound_3d_test.cpp deleted file mode 100644 index f5b197fd0..000000000 --- a/libs/openengine/sound/tests/sound_3d_test.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include - -#include -#include - -#include - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; -using namespace OEngine::Sound; - -const std::string sound = "../../mangle/sound/tests/cow.wav"; - -SoundManagerPtr m; - -// Play and wait for finish -void play(float x, float y, float z) -{ - cout << "Playing at " << x << "," << y << "," << z << endl; - - SoundPtr snd = m->play3D(sound,x,y,z); - - while(snd->isPlaying()) - { - usleep(10000); - m->update(); - } -} - -int main() -{ - SoundFactoryPtr oaf(new OpenAL_Audiere_Factory); - SoundManagerPtr mg(new SoundManager(oaf)); - m = mg; - - mg->setListenerPos(0,0,0,0,1,0,0,0,1); - - play(0,0,0); - play(1,1,0); - play(-1,0,0); - - return 0; -} diff --git a/libs/openengine/sound/tests/sound_manager_test.cpp b/libs/openengine/sound/tests/sound_manager_test.cpp deleted file mode 100644 index 3794c4a3c..000000000 --- a/libs/openengine/sound/tests/sound_manager_test.cpp +++ /dev/null @@ -1,73 +0,0 @@ -#include -#include -#include - -#include -#include - -#include - -using namespace std; -using namespace Mangle::Stream; -using namespace Mangle::Sound; -using namespace OEngine::Sound; - -const std::string sound = "../../mangle/sound/tests/cow.wav"; - -int main() -{ - SoundFactoryPtr oaf(new OpenAL_Audiere_Factory); - SoundManagerPtr mg(new SoundManager(oaf)); - - cout << "Playing " << sound << "\n"; - - assert(mg->numSounds() == 0); - - /** Start the sound playing, and then let the pointer go out of - scope. Lower-level players (like 'oaf' above) will immediately - delete the sound. SoundManager OTOH will keep it until it's - finished. - */ - mg->play(sound); - - assert(mg->numSounds() == 1); - - // Loop while there are still sounds to manage - while(mg->numSounds() != 0) - { - assert(mg->numSounds() == 1); - usleep(10000); - if(mg->needsUpdate) - mg->update(); - } - - SoundPtr snd = mg->play(sound); - cout << "Replaying\n"; - int i = 0; - while(mg->numSounds() != 0) - { - assert(mg->numSounds() == 1); - usleep(10000); - if(mg->needsUpdate) - mg->update(); - - if(i++ == 70) - { - cout << "pause\n"; - snd->pause(); - } - if(i == 130) - { - cout << "restart\n"; - snd->play(); - // Let the sound go out of scope - snd.reset(); - } - } - - cout << "Done playing.\n"; - - assert(mg->numSounds() == 0); - - return 0; -} diff --git a/libs/openengine/sound/tests/test.sh b/libs/openengine/sound/tests/test.sh deleted file mode 100755 index 2d07708ad..000000000 --- a/libs/openengine/sound/tests/test.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash - -make || exit - -mkdir -p output - -PROGS=*_test - -for a in $PROGS; do - if [ -f "output/$a.out" ]; then - echo "Running $a:" - ./$a | diff output/$a.out - - else - echo "Creating $a.out" - ./$a > "output/$a.out" - git add "output/$a.out" - fi -done diff --git a/readme.txt b/readme.txt index 8f360235f..36a732015 100644 --- a/readme.txt +++ b/readme.txt @@ -7,6 +7,10 @@ Version: 0.13.0 License: GPL (see GPL3.txt for more information) Website: http://www.openmw.org +Font Licenses: +EBGaramond-Regular.ttf: OFL (see OFL.txt for more information) +VeraMono.ttf: custom (see Bitstream Vera License.txt for more information) + THIS IS A WORK IN PROGRESS