diff --git a/bin/conf/gui.conf.default b/bin/conf/gui.conf.default index fbf51c6..40765ef 100644 --- a/bin/conf/gui.conf.default +++ b/bin/conf/gui.conf.default @@ -23,6 +23,11 @@ shadows=1 // color depth; 16 or 32 bit depth=32 +// Use Sound? (experimental) +// 1: Yes +// 0: No (default) +UseSound=1 + //================================================================================================ // Expert options: Renderer finetuning diff --git a/bin/data/misc/main_theme.ogg b/bin/data/misc/main_theme.ogg new file mode 100644 index 0000000..68a12e7 Binary files /dev/null and b/bin/data/misc/main_theme.ogg differ diff --git a/bin/ikpMP3.dll b/bin/ikpMP3.dll new file mode 100644 index 0000000..02b8bc5 Binary files /dev/null and b/bin/ikpMP3.dll differ diff --git a/bin/ikpMP3.so b/bin/ikpMP3.so new file mode 100644 index 0000000..fc3804c Binary files /dev/null and b/bin/ikpMP3.so differ diff --git a/bin/irrKlang.dll b/bin/irrKlang.dll new file mode 100644 index 0000000..64ee37b Binary files /dev/null and b/bin/irrKlang.dll differ diff --git a/bin/libIrrKlang.so b/bin/libIrrKlang.so new file mode 100644 index 0000000..2169726 Binary files /dev/null and b/bin/libIrrKlang.so differ diff --git a/src/Client/GUI/CIrrKlangAudioStreamLoaderMP3.cpp b/src/Client/GUI/CIrrKlangAudioStreamLoaderMP3.cpp new file mode 100644 index 0000000..448eac6 --- /dev/null +++ b/src/Client/GUI/CIrrKlangAudioStreamLoaderMP3.cpp @@ -0,0 +1,42 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "irrKlang" library. +// For conditions of distribution and use, see copyright notice in irrKlang.h + +#include "CIrrKlangAudioStreamLoaderMP3.h" +#include "CIrrKlangAudioStreamMP3.h" +#include + + +namespace irrklang +{ + + +CIrrKlangAudioStreamLoaderMP3::CIrrKlangAudioStreamLoaderMP3() +{ +} + + +//! Returns true if the file maybe is able to be loaded by this class. +bool CIrrKlangAudioStreamLoaderMP3::isALoadableFileExtension(const ik_c8* fileName) +{ + return strstr(fileName, ".mp3") != 0; +} + + +//! Creates an audio file input stream from a file +IAudioStream* CIrrKlangAudioStreamLoaderMP3::createAudioStream(irrklang::IFileReader* file) +{ + CIrrKlangAudioStreamMP3* stream = new CIrrKlangAudioStreamMP3(file); + + if (stream && !stream->isOK()) + { + stream->drop(); + stream = 0; + } + + return stream; +} + + +} // end namespace irrklang + diff --git a/src/Client/GUI/CIrrKlangAudioStreamLoaderMP3.h b/src/Client/GUI/CIrrKlangAudioStreamLoaderMP3.h new file mode 100644 index 0000000..e5a377d --- /dev/null +++ b/src/Client/GUI/CIrrKlangAudioStreamLoaderMP3.h @@ -0,0 +1,32 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// This file is part of the "irrKlang" library. +// For conditions of distribution and use, see copyright notice in irrKlang.h + +#ifndef __C_IRRKLANG_AUDIO_STREAM_LOADER_MP3_H_INCLUDED__ +#define __C_IRRKLANG_AUDIO_STREAM_LOADER_MP3_H_INCLUDED__ + +#include "irrklang/ik_IAudioStreamLoader.h" + +namespace irrklang +{ + //! Class which is able to create an audio file stream from a file. + class CIrrKlangAudioStreamLoaderMP3 : public IAudioStreamLoader + { + public: + + CIrrKlangAudioStreamLoaderMP3(); + + //! Returns true if the file maybe is able to be loaded by this class. + /** This decision should be based only on the file extension (e.g. ".wav") */ + virtual bool isALoadableFileExtension(const ik_c8* fileName); + + //! Creates an audio file input stream from a file + /** \return Pointer to the created audio stream. Returns 0 if loading failed. + If you no longer need the stream, you should call IAudioFileStream::drop(). + See IRefCounted::drop() for more information. */ + virtual IAudioStream* createAudioStream(irrklang::IFileReader* file); + }; + +} // end namespace irrklang + +#endif diff --git a/src/Client/GUI/CIrrKlangAudioStreamMP3.cpp b/src/Client/GUI/CIrrKlangAudioStreamMP3.cpp new file mode 100644 index 0000000..0deed57 --- /dev/null +++ b/src/Client/GUI/CIrrKlangAudioStreamMP3.cpp @@ -0,0 +1,397 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Part of the code for this plugin for irrKlang is based on: +// MP3 input for Audiere by Matt Campbell , based on +// libavcodec from ffmpeg (http://ffmpeg.sourceforge.net/). +// See license.txt for license details of this plugin. + +#include "CIrrKlangAudioStreamMP3.h" +#include +#include // free, malloc and realloc +#include + +namespace irrklang +{ + +CIrrKlangAudioStreamMP3::CIrrKlangAudioStreamMP3(IFileReader* file) +: File(file), TheMPAuDecContext(0), InputPosition(0), InputLength(0), + DecodeBuffer(0), FirstFrameRead(false), EndOfFileReached(0), + FileBegin(0), Position(0) +{ + if (File) + { + File->grab(); + + TheMPAuDecContext = new MPAuDecContext(); + + if (!TheMPAuDecContext || mpaudec_init(TheMPAuDecContext) < 0) + { + File->drop(); + File = 0; + delete TheMPAuDecContext; + TheMPAuDecContext = 0; + return; + } + + // init, get format + + DecodeBuffer = new ik_u8[MPAUDEC_MAX_AUDIO_FRAME_SIZE]; + + if (File->getSize()>0) + { + // seekable file, now parse file to get size + // (needed to make it possible for the engine to loop a stream correctly) + + skipID3IfNecessary(); + + TheMPAuDecContext->parse_only = 1; + Format.FrameCount = 0; + + while(!EndOfFileReached) + { + if (!decodeFrame()) + break; + + Format.FrameCount += TheMPAuDecContext->frame_size; + + if (!EndOfFileReached /*&& File->isSeekable()*/ ) + { + // to be able to seek in the stream, store offsets and sizes + + SFramePositionData data; + data.size = TheMPAuDecContext->frame_size; + data.offset = File->getPos() - (InputLength - InputPosition) - TheMPAuDecContext->coded_frame_size; + + FramePositionData.push_back(data); + } + } + + TheMPAuDecContext->parse_only = 0; + setPosition(0); + } + else + decodeFrame(); // decode first frame to read audio format + + if (!TheMPAuDecContext->channels || + !TheMPAuDecContext->sample_rate ) + { + File->drop(); + File = 0; + delete TheMPAuDecContext; + TheMPAuDecContext = 0; + return; + } + } +} + +CIrrKlangAudioStreamMP3::~CIrrKlangAudioStreamMP3() +{ + if (File) + File->drop(); + + if (TheMPAuDecContext) + { + mpaudec_clear(TheMPAuDecContext); + delete TheMPAuDecContext; + } + + delete [] DecodeBuffer; +} + + + +//! returns format of the audio stream +SAudioStreamFormat CIrrKlangAudioStreamMP3::getFormat() +{ + return Format; +} + + +//! tells the audio stream to read n audio frames into the specified buffer +ik_s32 CIrrKlangAudioStreamMP3::readFrames(void* target, ik_s32 frameCountToRead) +{ + const int frameSize = Format.getFrameSize(); + + int framesRead = 0; + ik_u8* out = (ik_u8*)target; + + while (framesRead < frameCountToRead) + { + // no more samples? ask the MP3 for more + if (DecodedQueue.getSize() < frameSize) + { + if (!decodeFrame() || EndOfFileReached) + return framesRead; + + // if the buffer is still empty, we are done + if (DecodedQueue.getSize() < frameSize) + return framesRead; + } + + const int framesLeft = frameCountToRead - framesRead; + const int dequeSize = DecodedQueue.getSize() / frameSize; + const int framesToRead = framesLeft < dequeSize ? framesLeft : dequeSize; + + DecodedQueue.read(out, framesToRead * frameSize); + + out += framesToRead * frameSize; + framesRead += framesToRead; + Position += framesToRead; + } + + return framesRead; +} + + + +bool CIrrKlangAudioStreamMP3::decodeFrame() +{ + int outputSize = 0; + + while (!outputSize) + { + if (InputPosition == InputLength) + { + InputPosition = 0; + InputLength = File->read(InputBuffer, IKP_MP3_INPUT_BUFFER_SIZE); + + if (InputLength == 0) + { + EndOfFileReached = true; + return true; + } + } + + int rv = mpaudec_decode_frame( TheMPAuDecContext, (ik_s16*)DecodeBuffer, + &outputSize, + (ik_u8*)InputBuffer + InputPosition, + InputLength - InputPosition); + + if (rv < 0) + return false; + + InputPosition += rv; + } // end while + + if (!FirstFrameRead) + { + Format.ChannelCount = TheMPAuDecContext->channels; + Format.SampleRate = TheMPAuDecContext->sample_rate; + Format.SampleFormat = ESF_S16; + Format.FrameCount = -1; // unknown lenght + + FirstFrameRead = true; + } + else + if (TheMPAuDecContext->channels != Format.ChannelCount || + TheMPAuDecContext->sample_rate != Format.SampleRate) + { + // Can't handle format changes mid-stream. + return false; + } + + if (!TheMPAuDecContext->parse_only) + { + if (outputSize < 0) + { + // Couldn't decode this frame. Too bad, already lost it. + // This should only happen when seeking. + + outputSize = TheMPAuDecContext->frame_size; + memset(DecodeBuffer, 0, outputSize * Format.getFrameSize()); + } + + DecodedQueue.write(DecodeBuffer, outputSize); + } + + return true; +} + + + +//! sets the position of the audio stream. +/** For example to let the stream be read from the beginning of the file again, +setPosition(0) would be called. This is usually done be the sound engine to +loop a stream after if has reached the end. Return true if sucessful and 0 if not. */ +bool CIrrKlangAudioStreamMP3::setPosition(ik_s32 pos) +{ + if (!File || !TheMPAuDecContext) + return false; + + if (pos == 0) + { + // usually done for looping, just reset to start + + File->seek(FileBegin); // skip possible ID3 header + + EndOfFileReached = false; + + DecodedQueue.clear(); + + MPAuDecContext oldContext = *TheMPAuDecContext; + + mpaudec_clear(TheMPAuDecContext); + mpaudec_init(TheMPAuDecContext); + + TheMPAuDecContext->bit_rate = oldContext.bit_rate; + TheMPAuDecContext->channels = oldContext.channels; + TheMPAuDecContext->frame_size = oldContext.frame_size; + TheMPAuDecContext->sample_rate = oldContext.sample_rate; + + InputPosition = 0; + InputLength = 0; + Position = 0; + CurrentFramePosition = 0; + + return true; + } + else + { + // user wants to seek in the stream, so do this here + + int scan_position = 0; + int target_frame = 0; + int frame_count = (int)FramePositionData.size(); + + while (target_frame < frame_count) + { + int frame_size = FramePositionData[target_frame].size; + + if (pos <= scan_position + frame_size) + break; + else + { + scan_position += frame_size; + target_frame++; + } + } + + + const int MAX_FRAME_DEPENDENCY = 10; + target_frame = std::max(0, target_frame - MAX_FRAME_DEPENDENCY); + setPosition(0); + + File->seek(FramePositionData[target_frame].offset, false); + + int i; + for (i = 0; i < target_frame; i++) + { + if (i>=(int)FramePositionData.size()) + { + // internal error + setPosition(0); + return false; + } + + Position += FramePositionData[i].size; + } + + if (!decodeFrame() || EndOfFileReached) + { + setPosition(0); + return false; + } + + int frames_to_consume = pos - Position; // PCM frames now + if (frames_to_consume > 0) + { + ik_u8 *buf = new ik_u8[frames_to_consume * Format.getFrameSize()]; + readFrames(buf, frames_to_consume); + delete[] buf; + } + + return true; + } + + return false; +} + + +CIrrKlangAudioStreamMP3::QueueBuffer::QueueBuffer() +{ + Capacity = 256; + Size = 0; + + Buffer = (ik_u8*)malloc(Capacity); +} + + +CIrrKlangAudioStreamMP3::QueueBuffer::~QueueBuffer() +{ + free(Buffer); +} + +int CIrrKlangAudioStreamMP3::QueueBuffer::getSize() +{ + return Size; +} + +void CIrrKlangAudioStreamMP3::QueueBuffer::write(const void* buffer, int size) +{ + bool needRealloc = false; + + while (size + Size > Capacity) + { + Capacity *= 2; + needRealloc = true; + } + + if (needRealloc) + { + Buffer = (ik_u8*)realloc(Buffer, Capacity); + } + + memcpy(Buffer + Size, buffer, size); + Size += size; +} + + +int CIrrKlangAudioStreamMP3::QueueBuffer::read(void* buffer, int size) +{ + int toRead = size < Size ? size : Size; + + memcpy(buffer, Buffer, toRead); + memmove(Buffer, Buffer + toRead, Size - toRead); + + Size -= toRead; + return toRead; +} + + +void CIrrKlangAudioStreamMP3::QueueBuffer::clear() +{ + Size = 0; +} + + +void CIrrKlangAudioStreamMP3::skipID3IfNecessary() +{ + char header[10]; + int read = File->read(&header, 10); + + if (read == 10 && + header[0] == 'I' && header[1] == 'D' && header[2] == '3') + { + int versionMajor = header[3]; + int versionMinor = header[4]; + int flags = header[5]; + + // IDv2 size looks like the following: ID3v2 size 4 * %0xxxxxxx. + // Sick, but that's how it works. + + int size = 0; + size = (header[6] & 0x7f) << (3*7); + size |= (header[7] & 0x7f) << (2*7); + size |= (header[8] & 0x7f) << (1*7); + size |= (header[9] & 0x7f) ; + + size += 10; // header size + + FileBegin = size; + File->seek(FileBegin); + } + else + File->seek(0); +} + + +} // end namespace irrklang diff --git a/src/Client/GUI/CIrrKlangAudioStreamMP3.h b/src/Client/GUI/CIrrKlangAudioStreamMP3.h new file mode 100644 index 0000000..8f5a626 --- /dev/null +++ b/src/Client/GUI/CIrrKlangAudioStreamMP3.h @@ -0,0 +1,106 @@ +// Copyright (C) 2002-2007 Nikolaus Gebhardt +// Part of the code for this plugin for irrKlang is based on: +// MP3 input for Audiere by Matt Campbell , based on +// libavcodec from ffmpeg (http://ffmpeg.sourceforge.net/). +// See license.txt for license details of this plugin. + +#ifndef __C_IRRKLANG_AUDIO_STREAM_MP3_H_INCLUDED__ +#define __C_IRRKLANG_AUDIO_STREAM_MP3_H_INCLUDED__ + +#include "irrklang/ik_IAudioStream.h" +#include "irrklang/ik_IFileReader.h" +#include +#include "decoder/mpaudec.h" + +namespace irrklang +{ + const int IKP_MP3_INPUT_BUFFER_SIZE = 4096; + + //! Reads and decodes audio data into an usable audio stream for the ISoundEngine + /** To extend irrKlang with new audio format decoders, the only thing needed to do + is implementing the IAudioStream interface. All the code available in this class is only for + mp3 decoding and may make this class look a bit more complicated then it actually is. */ + class CIrrKlangAudioStreamMP3 : public IAudioStream + { + public: + + CIrrKlangAudioStreamMP3(IFileReader* file); + ~CIrrKlangAudioStreamMP3(); + + //! returns format of the audio stream + virtual SAudioStreamFormat getFormat(); + + //! tells the audio stream to read n audio frames into the specified buffer + /** \param target: Target data buffer to the method will write the read frames into. The + specified buffer will be getFormat().getFrameSize()*frameCount big. + \param frameCount: amount of frames to be read. + \returns Returns amount of frames really read. Should be frameCountToRead in most cases. */ + virtual ik_s32 readFrames(void* target, ik_s32 frameCountToRead); + + //! sets the position of the audio stream. + /** For example to let the stream be read from the beginning of the file again, + setPosition(0) would be called. This is usually done be the sound engine to + loop a stream after if has reached the end. Return true if sucessful and 0 if not. */ + virtual bool setPosition(ik_s32 pos); + + // just for the CIrrKlangAudioStreamLoaderMP3 to let him know if loading worked + bool isOK() { return File != 0; } + + protected: + + ik_s32 readFrameForMP3(void* target, ik_s32 frameCountToRead, bool parseOnly=false); + bool decodeFrame(); + void skipID3IfNecessary(); + + irrklang::IFileReader* File; + SAudioStreamFormat Format; + + // mpaudec specific + MPAuDecContext* TheMPAuDecContext; + + ik_u8 InputBuffer[IKP_MP3_INPUT_BUFFER_SIZE]; + + int InputPosition; + int InputLength; + int Position; + ik_u8* DecodeBuffer; + ik_s32 FileBegin; + ik_u32 CurrentFramePosition; + + bool FirstFrameRead; + bool EndOfFileReached; + + // helper class for managing the streaming decoded audio data + class QueueBuffer + { + public: + + QueueBuffer(); + ~QueueBuffer(); + + int getSize(); + void write(const void* buffer, int size); + int read(void* buffer, int size); + void clear(); + + private: + + ik_u8* Buffer; + int Capacity; + int Size; + }; + + struct SFramePositionData + { + int offset; + int size; + }; + + std::vector FramePositionData; + QueueBuffer DecodedQueue; + }; + + +} // end namespace irrklang + +#endif diff --git a/src/Client/GUI/PseuGUI.cpp b/src/Client/GUI/PseuGUI.cpp index 3956b4a..0d03865 100644 --- a/src/Client/GUI/PseuGUI.cpp +++ b/src/Client/GUI/PseuGUI.cpp @@ -45,7 +45,9 @@ PseuGUI::PseuGUI() _guienv = NULL; _scene = NULL; _passtime = _lastpasstime = _passtimediff = 0; - } + _soundengine = NULL; + _usesound = false; +} PseuGUI::~PseuGUI() { @@ -131,6 +133,16 @@ void PseuGUI::_Init(void) _smgr->addExternalMeshLoader(m2loader); _throttle=0; _initialized = true; + + // initialize the sound engine + if(_usesound) + { + _soundengine = createIrrKlangDevice(); + if(_soundengine) + logdetail("PseuGUI: Sound Driver: %s",_soundengine->getDriverName()); + else + logerror("PseuGUI: Failed to initialize sound engine!"); + } } void PseuGUI::Cancel(void) @@ -147,7 +159,11 @@ void PseuGUI::Cancel(void) { _device->drop(); _device = NULL; - + } + if(_soundengine) + { + _soundengine->drop(); + _soundengine = NULL; } _mustdie = true; } diff --git a/src/Client/GUI/PseuGUI.h b/src/Client/GUI/PseuGUI.h index cea3f86..e9e076f 100644 --- a/src/Client/GUI/PseuGUI.h +++ b/src/Client/GUI/PseuGUI.h @@ -2,6 +2,7 @@ #define PSEUGUI_H #include "irrlicht/irrlicht.h" +#include "irrklang/irrKlang.h" #include "SceneData.h" #include "DrawObjMgr.h" #include "World.h" @@ -89,6 +90,7 @@ public: void Cancel(void); void Shutdown(void); inline bool IsInitialized(void) { return _initialized && _device; } + inline void SetUseSound(bool b) { _usesound = b; } inline bool MustDie(void) { return _mustdie; } @@ -112,11 +114,13 @@ private: uint16 _xres,_yres,_colordepth; bool _windowed,_vsync,_shadows; bool _initialized,_mustdie; + bool _usesound; irr::IrrlichtDevice *_device; irr::video::IVideoDriver* _driver; irr::scene::ISceneManager* _smgr; irr::gui::IGUIEnvironment* _guienv; irr::video::E_DRIVER_TYPE _driverType; + irrklang::ISoundEngine *_soundengine; DrawObjMgr domgr; PseuInstance *_instance; SceneState _scenestate, _scenestate_new; diff --git a/src/Client/GUI/Scene.cpp b/src/Client/GUI/Scene.cpp index 3e0bfdc..833ec5d 100644 --- a/src/Client/GUI/Scene.cpp +++ b/src/Client/GUI/Scene.cpp @@ -18,6 +18,8 @@ Scene::Scene(PseuGUI *g) cursor->setOSCursorVisible(true); cursor->setVisible(false); cursor->render(); // apply above settings + + soundengine = gui->_soundengine; } void Scene::OnDraw(void) diff --git a/src/Client/GUI/Scene.h b/src/Client/GUI/Scene.h index 7674536..a9ee333 100644 --- a/src/Client/GUI/Scene.h +++ b/src/Client/GUI/Scene.h @@ -1,136 +1,138 @@ -#ifndef _SCENE_H -#define _SCENE_H - -#include "irrlicht/irrlicht.h" -#include "SceneData.h" - -using namespace irr; -using namespace core; -using namespace scene; -using namespace video; -using namespace io; -using namespace gui; - - -class PseuGUI; -class CCursorController; - -// base class -class Scene -{ - friend class PseuGUI; -public: - Scene(PseuGUI *g); - ~Scene(); - core::stringw GetStringFromDB(u32 index, u32 entry); - inline void SetState(SceneState sc) { _scenestate = sc; } - inline SceneState GetState(void) { return _scenestate; } - virtual void OnUpdate(s32); - virtual void OnDraw(void); - virtual void OnDrawBegin(void); - virtual void OnDelete(void); - virtual video::SColor GetBackgroundColor(void); - virtual void SetData(uint32 index, uint32 value) { scenedata[index] = value; } -protected: - PseuInstance *instance; - PseuGUI *gui; - irr::IrrlichtDevice *device; - irr::video::IVideoDriver* driver; - irr::scene::ISceneManager* smgr; - irr::gui::IGUIEnvironment* guienv; - CCursorController *cursor; - SceneState _scenestate; - uint32 scenedata[SCENEDATA_SIZE]; // generic storage for anything the PseuInstance thread wants to tell us - SCPDatabase *textdb; -}; - -class SceneGuiStart : public Scene -{ -public: - SceneGuiStart(PseuGUI *gui); - void OnDelete(void); -private: - IGUIImage *irrlogo, *driverlogo; - -}; - -class GUIEventReceiver; - -class SceneLogin : public Scene -{ -public: - SceneLogin(PseuGUI *gui); - void OnUpdate(s32); - void OnDelete(void); - -private: - gui::IGUIElement* root; - IGUIImage *irrlogo, *background; - GUIEventReceiver *eventrecv; - PseuGUI* _gui; - gui::IGUIElement *msgbox; - uint32 msgbox_textid; -}; - -class ShTlTerrainSceneNode; -class MCameraFPS; -class MCameraOrbit; -class MyEventReceiver; -class MapMgr; -class WorldSession; -class MovementMgr; -class MyCharacter; - -class SceneWorld : public Scene -{ - struct SceneNodeWithGridPos - { - scene::ISceneNode *scenenode; - uint32 gx,gy; - }; - -public: - SceneWorld(PseuGUI *gui); - void OnDraw(void); - void OnDrawBegin(void); - void OnDelete(void); - void OnUpdate(s32); - void UpdateTerrain(void); - void InitTerrain(void); - void RelocateCamera(void); - void RelocateCameraBehindChar(void); - void UpdateDoodads(void); - scene::ISceneNode *GetMyCharacterSceneNode(void); - video::SColor GetBackgroundColor(void); - - WorldPosition GetWorldPosition(void); - -private: - ShTlTerrainSceneNode *terrain; - MCameraFPS *camera; - MyEventReceiver *eventrecv; - ZThread::FastMutex mutex; - PseuGUI *gui; - uint32 map_gridX, map_gridY; - WorldSession *wsession; - World *world; - MapMgr *mapmgr; - IGUIStaticText *debugText; - bool debugmode; - std::map _doodads; - scene::ISceneNode *sky; - scene::ISceneNode *selectedNode, *oldSelectedNode, *focusedNode, *oldFocusedNode; - video::SColor envBasicColor; - MovementMgr *movemgr; - MyCharacter *mychar; - bool _freeCameraMove; - void _CalcXYMoveVect(float o); - core::vector2df xyCharMovement; // stores sin() and cos() values for current MyCharacter orientation, so that they need to be calculated only if the character turns around - bool mouse_pressed_left; - bool mouse_pressed_right; - float old_char_o; -}; - - - -#endif +#ifndef _SCENE_H +#define _SCENE_H + +#include "irrlicht/irrlicht.h" +#include "SceneData.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; +using namespace irrklang; + + +class PseuGUI; +class CCursorController; + +// base class +class Scene +{ + friend class PseuGUI; +public: + Scene(PseuGUI *g); + ~Scene(); + core::stringw GetStringFromDB(u32 index, u32 entry); + inline void SetState(SceneState sc) { _scenestate = sc; } + inline SceneState GetState(void) { return _scenestate; } + virtual void OnUpdate(s32); + virtual void OnDraw(void); + virtual void OnDrawBegin(void); + virtual void OnDelete(void); + virtual video::SColor GetBackgroundColor(void); + virtual void SetData(uint32 index, uint32 value) { scenedata[index] = value; } +protected: + PseuInstance *instance; + PseuGUI *gui; + irr::IrrlichtDevice *device; + irr::video::IVideoDriver* driver; + irr::scene::ISceneManager* smgr; + irr::gui::IGUIEnvironment* guienv; + irrklang::ISoundEngine *soundengine; + CCursorController *cursor; + SceneState _scenestate; + uint32 scenedata[SCENEDATA_SIZE]; // generic storage for anything the PseuInstance thread wants to tell us + SCPDatabase *textdb; +}; + +class SceneGuiStart : public Scene +{ +public: + SceneGuiStart(PseuGUI *gui); + void OnDelete(void); +private: + IGUIImage *irrlogo, *driverlogo; + +}; + +class GUIEventReceiver; + +class SceneLogin : public Scene +{ +public: + SceneLogin(PseuGUI *gui); + void OnUpdate(s32); + void OnDelete(void); + +private: + gui::IGUIElement* root; + IGUIImage *irrlogo, *background; + GUIEventReceiver *eventrecv; + PseuGUI* _gui; + gui::IGUIElement *msgbox; + uint32 msgbox_textid; +}; + +class ShTlTerrainSceneNode; +class MCameraFPS; +class MCameraOrbit; +class MyEventReceiver; +class MapMgr; +class WorldSession; +class MovementMgr; +class MyCharacter; + +class SceneWorld : public Scene +{ + struct SceneNodeWithGridPos + { + scene::ISceneNode *scenenode; + uint32 gx,gy; + }; + +public: + SceneWorld(PseuGUI *gui); + void OnDraw(void); + void OnDrawBegin(void); + void OnDelete(void); + void OnUpdate(s32); + void UpdateTerrain(void); + void InitTerrain(void); + void RelocateCamera(void); + void RelocateCameraBehindChar(void); + void UpdateDoodads(void); + scene::ISceneNode *GetMyCharacterSceneNode(void); + video::SColor GetBackgroundColor(void); + + WorldPosition GetWorldPosition(void); + +private: + ShTlTerrainSceneNode *terrain; + MCameraFPS *camera; + MyEventReceiver *eventrecv; + ZThread::FastMutex mutex; + PseuGUI *gui; + uint32 map_gridX, map_gridY; + WorldSession *wsession; + World *world; + MapMgr *mapmgr; + IGUIStaticText *debugText; + bool debugmode; + std::map _doodads; + scene::ISceneNode *sky; + scene::ISceneNode *selectedNode, *oldSelectedNode, *focusedNode, *oldFocusedNode; + video::SColor envBasicColor; + MovementMgr *movemgr; + MyCharacter *mychar; + bool _freeCameraMove; + void _CalcXYMoveVect(float o); + core::vector2df xyCharMovement; // stores sin() and cos() values for current MyCharacter orientation, so that they need to be calculated only if the character turns around + bool mouse_pressed_left; + bool mouse_pressed_right; + float old_char_o; +}; + + + +#endif diff --git a/src/Client/GUI/SceneLogin.cpp b/src/Client/GUI/SceneLogin.cpp index 7254b8b..ef7d514 100644 --- a/src/Client/GUI/SceneLogin.cpp +++ b/src/Client/GUI/SceneLogin.cpp @@ -70,6 +70,10 @@ SceneLogin::SceneLogin(PseuGUI *gui) : Scene(gui) guienv->addButton(rect((scrn.Width*0.5f)-60, (scrn.Height*0.3f)+100, (scrn.Width*0.5f)+60, (scrn.Height*0.3f)+130), 0, 16, L"Logon"); msgbox = guienv->addStaticText(GetStringFromDB(ISCENE_LOGIN_CONN_STATUS,DSCENE_LOGIN_NOT_CONNECTED).c_str(),rect((scrn.Width*0.5f)-90, (scrn.Height*0.3f)+150, (scrn.Width*0.5f)+90, (scrn.Height*0.3f)+180),true,true); + if(soundengine) + { + soundengine->play2D("data/misc/main_theme.ogg",true); + } } void SceneLogin::OnUpdate(s32 timepassed) @@ -114,6 +118,10 @@ void SceneLogin::OnUpdate(s32 timepassed) void SceneLogin::OnDelete(void) { + if(soundengine) + { + soundengine->stopAllSounds(); + } // not necessary to delete the images, because they are deleted by guienv->clear() } diff --git a/src/Client/GUI/SceneWorld.cpp b/src/Client/GUI/SceneWorld.cpp index 1c5a32d..a9e044d 100644 --- a/src/Client/GUI/SceneWorld.cpp +++ b/src/Client/GUI/SceneWorld.cpp @@ -368,7 +368,7 @@ void SceneWorld::OnUpdate(s32 timediff) } device->getCursorControl()->setPosition(mouse_pos); - // rotate character if right mpouse button pressed. + // rotate character if right mouse button pressed. if(mouse_pressed_right) { mychar->GetPositionPtr()->o = PI*3/2 - DEG_TO_RAD(camera->getHeading()); diff --git a/src/Client/GUI/decoder/bits.c b/src/Client/GUI/decoder/bits.c new file mode 100644 index 0000000..d7657e4 --- /dev/null +++ b/src/Client/GUI/decoder/bits.c @@ -0,0 +1,273 @@ +/* + * Common bit i/o utils + * Copyright (c) 2000, 2001 Fabrice Bellard. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Modified by Matt Campbell for the stand-alone + * mpaudec library. Based on common.c from libavcodec. + */ + +#include "internal.h" + +/** + * init GetBitContext. + * @param buffer bitstream buffer + * @param bit_size the size of the buffer in bits + */ +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int bit_size) +{ + s->buffer= buffer; + s->size_in_bits= bit_size; + s->index=0; +} + +unsigned int show_bits(const GetBitContext *s, int n) +{ + int i; + unsigned int result = 0; + assert(s->size_in_bits - s->index >= n); + for (i = s->index; i < s->index + n; i++) { + int byte_index = i / 8; + unsigned int right_shift = 7 - (i % 8); + uint8_t byte = s->buffer[byte_index]; + uint8_t bit; + result <<= 1; + if (right_shift == 0) + bit = byte & 0x1; + else + bit = (byte >> right_shift) & 0x1; + result |= (unsigned int)bit; + } + return result; +} + +void skip_bits(GetBitContext *s, int n) +{ + s->index += n; +} + +unsigned int get_bits(GetBitContext *s, int n) +{ + unsigned int result = show_bits(s, n); + skip_bits(s, n); + return result; +} + +int get_bits_count(const GetBitContext *s) +{ + return s->index; +} + +/* VLC decoding */ + +/*#define DEBUG_VLC*/ + +#define GET_DATA(v, table, i, wrap, size) \ +{\ + const uint8_t *ptr = (const uint8_t *)table + i * wrap;\ + switch(size) {\ + case 1:\ + v = *(const uint8_t *)ptr;\ + break;\ + case 2:\ + v = *(const uint16_t *)ptr;\ + break;\ + default:\ + v = *(const uint32_t *)ptr;\ + break;\ + }\ +} + + +static int alloc_table(VLC *vlc, int size) +{ + int index; + index = vlc->table_size; + vlc->table_size += size; + if (vlc->table_size > vlc->table_allocated) { + vlc->table_allocated += (1 << vlc->bits); + vlc->table = realloc(vlc->table, + sizeof(VLC_TYPE) * 2 * vlc->table_allocated); + if (!vlc->table) + return -1; + } + return index; +} + +static int build_table(VLC *vlc, int table_nb_bits, + int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + uint32_t code_prefix, int n_prefix) +{ + int i, j, k, n, table_size, table_index, nb, n1, index; + uint32_t code; + VLC_TYPE (*table)[2]; + + table_size = 1 << table_nb_bits; + table_index = alloc_table(vlc, table_size); +#ifdef DEBUG_VLC + printf("new table index=%d size=%d code_prefix=%x n=%d\n", + table_index, table_size, code_prefix, n_prefix); +#endif + if (table_index < 0) + return -1; + table = &vlc->table[table_index]; + + for(i=0;i 0 && (code >> n) == code_prefix) { + if (n <= table_nb_bits) { + /* no need to add another table */ + j = (code << (table_nb_bits - n)) & (table_size - 1); + nb = 1 << (table_nb_bits - n); + for(k=0;k> n) & ((1 << table_nb_bits) - 1); +#ifdef DEBUG_VLC + printf("%4x: n=%d (subtable)\n", + j, n); +#endif + /* compute table size */ + n1 = -table[j][1]; /*bits*/ + if (n > n1) + n1 = n; + table[j][1] = -n1; /*bits*/ + } + } + } + + /* second pass : fill auxillary tables recursively */ + for(i=0;i table_nb_bits) { + n = table_nb_bits; + table[i][1] = -n; /*bits*/ + } + index = build_table(vlc, n, nb_codes, + bits, bits_wrap, bits_size, + codes, codes_wrap, codes_size, + (code_prefix << table_nb_bits) | i, + n_prefix + table_nb_bits); + if (index < 0) + return -1; + /* note: realloc has been done, so reload tables */ + table = &vlc->table[table_index]; + table[i][0] = index; /*code*/ + } + } + return table_index; +} + + +/* Build VLC decoding tables suitable for use with get_vlc(). + + 'nb_bits' set thee decoding table size (2^nb_bits) entries. The + bigger it is, the faster is the decoding. But it should not be too + big to save memory and L1 cache. '9' is a good compromise. + + 'nb_codes' : number of vlcs codes + + 'bits' : table which gives the size (in bits) of each vlc code. + + 'codes' : table which gives the bit pattern of of each vlc code. + + 'xxx_wrap' : give the number of bytes between each entry of the + 'bits' or 'codes' tables. + + 'xxx_size' : gives the number of bytes of each entry of the 'bits' + or 'codes' tables. + + 'wrap' and 'size' allows to use any memory configuration and types + (byte/word/long) to store the 'bits' and 'codes' tables. +*/ +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size) +{ + vlc->bits = nb_bits; + vlc->table = NULL; + vlc->table_allocated = 0; + vlc->table_size = 0; +#ifdef DEBUG_VLC + printf("build table nb_codes=%d\n", nb_codes); +#endif + + if (build_table(vlc, nb_bits, nb_codes, + bits, bits_wrap, bits_size, + codes, codes_wrap, codes_size, + 0, 0) < 0) { + free(vlc->table); + return -1; + } + return 0; +} + + +void free_vlc(VLC *vlc) +{ + free(vlc->table); +} + +int get_vlc(GetBitContext *s, const VLC *vlc) +{ + int code = 0; + int depth = 0, max_depth = 3; + int n, index, bits = vlc->bits; + + do { + index = show_bits(s, bits) + code; + code = vlc->table[index][0]; + n = vlc->table[index][1]; + depth++; + + if (n < 0 && depth < max_depth) { + skip_bits(s, bits); + bits = -n; + } + } while (n < 0 && depth < max_depth); + + skip_bits(s, n); + return code; +} diff --git a/src/Client/GUI/decoder/internal.h b/src/Client/GUI/decoder/internal.h new file mode 100644 index 0000000..5588137 --- /dev/null +++ b/src/Client/GUI/decoder/internal.h @@ -0,0 +1,86 @@ +/* Based on common.h from libavcodec. Modified extensively by Matt Campbell + for the stand-alone mpaudec library. */ + +#ifndef INTERNAL_H +#define INTERNAL_H + +#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define CONFIG_WIN32 +#endif + +#include +#include +#include +#include +#include +#include +#include "mpaudec.h" + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif + +#ifdef CONFIG_WIN32 + +/* windows */ + +typedef unsigned short uint16_t; +typedef signed short int16_t; +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; +typedef signed char int8_t; +typedef signed int int32_t; +typedef signed __int64 int64_t; + +# ifdef _DEBUG +# define DEBUG +# endif + +/* CONFIG_WIN32 end */ +#else + +/* unix */ + +#include + +#endif /* !CONFIG_WIN32 */ + +/* debug stuff */ + +#if !defined(DEBUG) && !defined(NDEBUG) +# define NDEBUG +#endif +#include + +/* bit input */ + +typedef struct GetBitContext { + const uint8_t *buffer; + int index; + int size_in_bits; +} GetBitContext; + +int get_bits_count(const GetBitContext *s); + +#define VLC_TYPE int16_t + +typedef struct VLC { + int bits; + VLC_TYPE (*table)[2]; + int table_size, table_allocated; +} VLC; + +unsigned int get_bits(GetBitContext *s, int n); +unsigned int show_bits(const GetBitContext *s, int n); +void skip_bits(GetBitContext *s, int n); +void init_get_bits(GetBitContext *s, + const uint8_t *buffer, int buffer_size); + +int init_vlc(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size); +void free_vlc(VLC *vlc); +int get_vlc(GetBitContext *s, const VLC *vlc); + +#endif /* INTERNAL_H */ diff --git a/src/Client/GUI/decoder/mpaudec.c b/src/Client/GUI/decoder/mpaudec.c new file mode 100644 index 0000000..a07289d --- /dev/null +++ b/src/Client/GUI/decoder/mpaudec.c @@ -0,0 +1,2477 @@ +/* + * MPEG Audio decoder + * Copyright (c) 2001, 2002 Fabrice Bellard. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Modified heavily by Matt Campbell for the + * stand-alone mpaudec library. Based on mpegaudiodec.c from libavcodec. + */ + +/*#define DEBUG*/ +#include "internal.h" +#include "mpegaudio.h" + +#ifdef _MSC_VER +#pragma warning(disable : 4244) +#endif + +/* + * TODO: + * - in low precision mode, use more 16 bit multiplies in synth filter + * - test lsf / mpeg25 extensively. + */ + +/* define USE_HIGHPRECISION to have a bit exact (but slower) mpeg + audio decoder */ +#define USE_HIGHPRECISION + +#ifdef USE_HIGHPRECISION +#define FRAC_BITS 23 /* fractional bits for sb_samples and dct */ +#define WFRAC_BITS 16 /* fractional bits for window */ +#else +#define FRAC_BITS 15 /* fractional bits for sb_samples and dct */ +#define WFRAC_BITS 14 /* fractional bits for window */ +#endif + +#define FRAC_ONE (1 << FRAC_BITS) + +#define MULL(a,b) (((int64_t)(a) * (int64_t)(b)) >> FRAC_BITS) +#define MUL64(a,b) ((int64_t)(a) * (int64_t)(b)) +#define FIX(a) ((int)((a) * FRAC_ONE)) +/* WARNING: only correct for posititive numbers */ +#define FIXR(a) ((int)((a) * FRAC_ONE + 0.5)) +#define FRAC_RND(a) (((a) + (FRAC_ONE/2)) >> FRAC_BITS) + +#if FRAC_BITS <= 15 +typedef int16_t MPA_INT; +#else +typedef int32_t MPA_INT; +#endif + +/****************/ + +#define HEADER_SIZE 4 +#define BACKSTEP_SIZE 512 + +typedef struct MPADecodeContext { + uint8_t inbuf1[2][MPA_MAX_CODED_FRAME_SIZE + BACKSTEP_SIZE]; /* input buffer */ + int inbuf_index; + uint8_t *inbuf_ptr, *inbuf; + int frame_size; + int free_format_frame_size; /* frame size in case of free format + (zero if currently unknown) */ + /* next header (used in free format parsing) */ + int error_protection; + int layer; + int sample_rate; + int sample_rate_index; /* between 0 and 8 */ + int bit_rate; + int old_frame_size; + GetBitContext gb; + int nb_channels; + int mode; + int mode_ext; + int lsf; + MPA_INT synth_buf[MPA_MAX_CHANNELS][512 * 2]; + int synth_buf_offset[MPA_MAX_CHANNELS]; + int32_t sb_samples[MPA_MAX_CHANNELS][36][SBLIMIT]; + int32_t mdct_buf[MPA_MAX_CHANNELS][SBLIMIT * 18]; /* previous samples, for layer 3 MDCT */ +#ifdef DEBUG + int frame_count; +#endif +} MPADecodeContext; + +/* layer 3 "granule" */ +typedef struct GranuleDef { + uint8_t scfsi; + int part2_3_length; + int big_values; + int global_gain; + int scalefac_compress; + uint8_t block_type; + uint8_t switch_point; + int table_select[3]; + int subblock_gain[3]; + uint8_t scalefac_scale; + uint8_t count1table_select; + int region_size[3]; /* number of huffman codes in each region */ + int preflag; + int short_start, long_end; /* long/short band indexes */ + uint8_t scale_factors[40]; + int32_t sb_hybrid[SBLIMIT * 18]; /* 576 samples */ +} GranuleDef; + +#define MODE_EXT_MS_STEREO 2 +#define MODE_EXT_I_STEREO 1 + +/* layer 3 huffman tables */ +typedef struct HuffTable { + int xsize; + const uint8_t *bits; + const uint16_t *codes; +} HuffTable; + +#include "mpaudectab.h" + +/* vlc structure for decoding layer 3 huffman tables */ +static VLC huff_vlc[16]; +static uint8_t *huff_code_table[16]; +static VLC huff_quad_vlc[2]; +/* computed from band_size_long */ +static uint16_t band_index_long[9][23]; +/* XXX: free when all decoders are closed */ +#define TABLE_4_3_SIZE (8191 + 16) +static int8_t table_4_3_exp[TABLE_4_3_SIZE]; +#if FRAC_BITS <= 15 +static uint16_t table_4_3_value[TABLE_4_3_SIZE]; +#else +static uint32_t table_4_3_value[TABLE_4_3_SIZE]; +#endif +/* intensity stereo coef table */ +static int32_t is_table[2][16]; +static int32_t is_table_lsf[2][2][16]; +static int32_t csa_table[8][2]; +static int32_t mdct_win[8][36]; + +/* lower 2 bits: modulo 3, higher bits: shift */ +static uint16_t scale_factor_modshift[64]; +/* [i][j]: 2^(-j/3) * FRAC_ONE * 2^(i+2) / (2^(i+2) - 1) */ +static int32_t scale_factor_mult[15][3]; +/* mult table for layer 2 group quantization */ + +#define SCALE_GEN(v) \ +{ FIXR(1.0 * (v)), FIXR(0.7937005259 * (v)), FIXR(0.6299605249 * (v)) } + +static int32_t scale_factor_mult2[3][3] = { + SCALE_GEN(4.0 / 3.0), /* 3 steps */ + SCALE_GEN(4.0 / 5.0), /* 5 steps */ + SCALE_GEN(4.0 / 9.0), /* 9 steps */ +}; + +/* 2^(n/4) */ +static uint32_t scale_factor_mult3[4] = { + FIXR(1.0), + FIXR(1.18920711500272106671), + FIXR(1.41421356237309504880), + FIXR(1.68179283050742908605), +}; + +static MPA_INT window[512]; + +/* layer 1 unscaling */ +/* n = number of bits of the mantissa minus 1 */ +static int l1_unscale(int n, int mant, int scale_factor) +{ + int shift, mod; + int64_t val; + + shift = scale_factor_modshift[scale_factor]; + mod = shift & 3; + shift >>= 2; + val = MUL64(mant + (-1 << n) + 1, scale_factor_mult[n-1][mod]); + shift += n; + /* NOTE: at this point, 1 <= shift >= 21 + 15 */ + return (int)((val + ((int64_t)(1) << (shift - 1))) >> shift); +} + +static int l2_unscale_group(int steps, int mant, int scale_factor) +{ + int shift, mod, val; + + shift = scale_factor_modshift[scale_factor]; + mod = shift & 3; + shift >>= 2; + + val = (mant - (steps >> 1)) * scale_factor_mult2[steps >> 2][mod]; + /* NOTE: at this point, 0 <= shift <= 21 */ + if (shift > 0) + val = (val + (1 << (shift - 1))) >> shift; + return val; +} + +/* compute value^(4/3) * 2^(exponent/4). It normalized to FRAC_BITS */ +static int l3_unscale(int value, int exponent) +{ +#if FRAC_BITS <= 15 + unsigned int m; +#else + uint64_t m; +#endif + int e; + + e = table_4_3_exp[value]; + e += (exponent >> 2); + e = FRAC_BITS - e; +#if FRAC_BITS <= 15 + if (e > 31) + e = 31; +#endif + m = table_4_3_value[value]; +#if FRAC_BITS <= 15 + m = (m * scale_factor_mult3[exponent & 3]); + m = (m + (1 << (e-1))) >> e; + return m; +#else + m = MUL64(m, scale_factor_mult3[exponent & 3]); + m = (m + ((uint64_t)(1) << (e-1))) >> e; + return (int)m; +#endif +} + +/* all integer n^(4/3) computation code */ +#define DEV_ORDER 13 + +#define POW_FRAC_BITS 24 +#define POW_FRAC_ONE (1 << POW_FRAC_BITS) +#define POW_FIX(a) ((int)((a) * POW_FRAC_ONE)) +#define POW_MULL(a,b) (((int64_t)(a) * (int64_t)(b)) >> POW_FRAC_BITS) + +static int dev_4_3_coefs[DEV_ORDER]; + +static int pow_mult3[3] = { + POW_FIX(1.0), + POW_FIX(1.25992104989487316476), + POW_FIX(1.58740105196819947474), +}; + +static void int_pow_init(void) +{ + int i, a; + + a = POW_FIX(1.0); + for(i=0;i= 0; j--) + a1 = POW_MULL(a, dev_4_3_coefs[j] + a1); + a = (1 << POW_FRAC_BITS) + a1; + /* exponent compute (exact) */ + e = e * 4; + er = e % 3; + eq = e / 3; + a = POW_MULL(a, pow_mult3[er]); + while (a >= 2 * POW_FRAC_ONE) { + a = a >> 1; + eq++; + } + /* convert to float */ + while (a < POW_FRAC_ONE) { + a = a << 1; + eq--; + } + /* now POW_FRAC_ONE <= a < 2 * POW_FRAC_ONE */ +#if POW_FRAC_BITS > FRAC_BITS + a = (a + (1 << (POW_FRAC_BITS - FRAC_BITS - 1))) >> (POW_FRAC_BITS - FRAC_BITS); + /* correct overflow */ + if (a >= 2 * (1 << FRAC_BITS)) { + a = a >> 1; + eq++; + } +#endif + *exp_ptr = eq; + return a; +} + +int mpaudec_init(MPAuDecContext * mpctx) +{ + MPADecodeContext *s; + static int init=0; + int i, j, k; + assert(mpctx != NULL); + memset(mpctx, 0, sizeof(MPAuDecContext)); + mpctx->priv_data = calloc(1, sizeof(MPADecodeContext)); + if (mpctx->priv_data == NULL) + return -1; + s = mpctx->priv_data; + + if (!init && !mpctx->parse_only) { + /* scale factors table for layer 1/2 */ + for(i=0;i<64;i++) { + int shift, mod; + /* 1.0 (i = 3) is normalized to 2 ^ FRAC_BITS */ + shift = (i / 3); + mod = i % 3; + scale_factor_modshift[i] = mod | (shift << 2); + } + + /* scale factor multiply for layer 1 */ + for(i=0;i<15;i++) { + int n, norm; + n = i + 2; + norm = (((int64_t)(1) << n) * FRAC_ONE) / ((1 << n) - 1); + scale_factor_mult[i][0] = MULL(FIXR(1.0 * 2.0), norm); + scale_factor_mult[i][1] = MULL(FIXR(0.7937005259 * 2.0), norm); + scale_factor_mult[i][2] = MULL(FIXR(0.6299605249 * 2.0), norm); +#ifdef DEBUG + printf("%d: norm=%x s=%x %x %x\n", + i, norm, + scale_factor_mult[i][0], + scale_factor_mult[i][1], + scale_factor_mult[i][2]); +#endif + } + + /* window */ + /* max = 18760, max sum over all 16 coefs : 44736 */ + for(i=0;i<257;i++) { + int v; + v = mpa_enwindow[i]; +#if WFRAC_BITS < 16 + v = (v + (1 << (16 - WFRAC_BITS - 1))) >> (16 - WFRAC_BITS); +#endif + window[i] = v; + if ((i & 63) != 0) + v = -v; + if (i != 0) + window[512 - i] = v; + } + + /* huffman decode tables */ + huff_code_table[0] = NULL; + for(i=1;i<16;i++) { + const HuffTable *h = &mpa_huff_tables[i]; + int xsize, x, y; + unsigned int n; + uint8_t *code_table; + + xsize = h->xsize; + n = xsize * xsize; + /* XXX: fail test */ + init_vlc(&huff_vlc[i], 8, n, + h->bits, 1, 1, h->codes, 2, 2); + + code_table = calloc(n, 1); + j = 0; + for(x=0;x> 1); + f = pow(2.0, e / 4.0); + k = i & 1; + is_table_lsf[j][k ^ 1][i] = FIXR(f); + is_table_lsf[j][k][i] = FIXR(1.0); +#ifdef DEBUG + printf("is_table_lsf %d %d: %x %x\n", + i, j, is_table_lsf[j][0][i], is_table_lsf[j][1][i]); +#endif + } + } + + for(i=0;i<8;i++) { + float ci, cs, ca; + ci = ci_table[i]; + cs = 1.0 / sqrt(1.0 + ci * ci); + ca = cs * ci; + csa_table[i][0] = FIX(cs); + csa_table[i][1] = FIX(ca); + } + + /* compute mdct windows */ + for(i=0;i<36;i++) { + int v; + v = FIXR(sin(M_PI * (i + 0.5) / 36.0)); + mdct_win[0][i] = v; + mdct_win[1][i] = v; + mdct_win[3][i] = v; + } + for(i=0;i<6;i++) { + mdct_win[1][18 + i] = FIXR(1.0); + mdct_win[1][24 + i] = FIXR(sin(M_PI * ((i + 6) + 0.5) / 12.0)); + mdct_win[1][30 + i] = FIXR(0.0); + + mdct_win[3][i] = FIXR(0.0); + mdct_win[3][6 + i] = FIXR(sin(M_PI * (i + 0.5) / 12.0)); + mdct_win[3][12 + i] = FIXR(1.0); + } + + for(i=0;i<12;i++) + mdct_win[2][i] = FIXR(sin(M_PI * (i + 0.5) / 12.0)); + + /* NOTE: we do frequency inversion adter the MDCT by changing + the sign of the right window coefs */ + for(j=0;j<4;j++) { + for(i=0;i<36;i+=2) { + mdct_win[j + 4][i] = mdct_win[j][i]; + mdct_win[j + 4][i + 1] = -mdct_win[j][i + 1]; + } + } + +#if defined(DEBUG) + for(j=0;j<8;j++) { + printf("win%d=\n", j); + for(i=0;i<36;i++) + printf("%f, ", (double)mdct_win[j][i] / FRAC_ONE); + printf("\n"); + } +#endif + init = 1; + } + + s->inbuf_index = 0; + s->inbuf = &s->inbuf1[s->inbuf_index][BACKSTEP_SIZE]; + s->inbuf_ptr = s->inbuf; +#ifdef DEBUG + s->frame_count = 0; +#endif + return 0; +} + +/* tab[i][j] = 1.0 / (2.0 * cos(pi*(2*k+1) / 2^(6 - j))) */ + +/* cos(i*pi/64) */ + +#define COS0_0 FIXR(0.50060299823519630134) +#define COS0_1 FIXR(0.50547095989754365998) +#define COS0_2 FIXR(0.51544730992262454697) +#define COS0_3 FIXR(0.53104259108978417447) +#define COS0_4 FIXR(0.55310389603444452782) +#define COS0_5 FIXR(0.58293496820613387367) +#define COS0_6 FIXR(0.62250412303566481615) +#define COS0_7 FIXR(0.67480834145500574602) +#define COS0_8 FIXR(0.74453627100229844977) +#define COS0_9 FIXR(0.83934964541552703873) +#define COS0_10 FIXR(0.97256823786196069369) +#define COS0_11 FIXR(1.16943993343288495515) +#define COS0_12 FIXR(1.48416461631416627724) +#define COS0_13 FIXR(2.05778100995341155085) +#define COS0_14 FIXR(3.40760841846871878570) +#define COS0_15 FIXR(10.19000812354805681150) + +#define COS1_0 FIXR(0.50241928618815570551) +#define COS1_1 FIXR(0.52249861493968888062) +#define COS1_2 FIXR(0.56694403481635770368) +#define COS1_3 FIXR(0.64682178335999012954) +#define COS1_4 FIXR(0.78815462345125022473) +#define COS1_5 FIXR(1.06067768599034747134) +#define COS1_6 FIXR(1.72244709823833392782) +#define COS1_7 FIXR(5.10114861868916385802) + +#define COS2_0 FIXR(0.50979557910415916894) +#define COS2_1 FIXR(0.60134488693504528054) +#define COS2_2 FIXR(0.89997622313641570463) +#define COS2_3 FIXR(2.56291544774150617881) + +#define COS3_0 FIXR(0.54119610014619698439) +#define COS3_1 FIXR(1.30656296487637652785) + +#define COS4_0 FIXR(0.70710678118654752439) + +/* butterfly operator */ +#define BF(a, b, c)\ +{\ + tmp0 = tab[a] + tab[b];\ + tmp1 = tab[a] - tab[b];\ + tab[a] = tmp0;\ + tab[b] = MULL(tmp1, c);\ +} + +#define BF1(a, b, c, d)\ +{\ + BF(a, b, COS4_0);\ + BF(c, d, -COS4_0);\ + tab[c] += tab[d];\ +} + +#define BF2(a, b, c, d)\ +{\ + BF(a, b, COS4_0);\ + BF(c, d, -COS4_0);\ + tab[c] += tab[d];\ + tab[a] += tab[c];\ + tab[c] += tab[b];\ + tab[b] += tab[d];\ +} + +#define ADD(a, b) tab[a] += tab[b] + +/* DCT32 without 1/sqrt(2) coef zero scaling. */ +static void dct32(int32_t *out, int32_t *tab) +{ + int tmp0, tmp1; + + /* pass 1 */ + BF(0, 31, COS0_0); + BF(1, 30, COS0_1); + BF(2, 29, COS0_2); + BF(3, 28, COS0_3); + BF(4, 27, COS0_4); + BF(5, 26, COS0_5); + BF(6, 25, COS0_6); + BF(7, 24, COS0_7); + BF(8, 23, COS0_8); + BF(9, 22, COS0_9); + BF(10, 21, COS0_10); + BF(11, 20, COS0_11); + BF(12, 19, COS0_12); + BF(13, 18, COS0_13); + BF(14, 17, COS0_14); + BF(15, 16, COS0_15); + + /* pass 2 */ + BF(0, 15, COS1_0); + BF(1, 14, COS1_1); + BF(2, 13, COS1_2); + BF(3, 12, COS1_3); + BF(4, 11, COS1_4); + BF(5, 10, COS1_5); + BF(6, 9, COS1_6); + BF(7, 8, COS1_7); + + BF(16, 31, -COS1_0); + BF(17, 30, -COS1_1); + BF(18, 29, -COS1_2); + BF(19, 28, -COS1_3); + BF(20, 27, -COS1_4); + BF(21, 26, -COS1_5); + BF(22, 25, -COS1_6); + BF(23, 24, -COS1_7); + + /* pass 3 */ + BF(0, 7, COS2_0); + BF(1, 6, COS2_1); + BF(2, 5, COS2_2); + BF(3, 4, COS2_3); + + BF(8, 15, -COS2_0); + BF(9, 14, -COS2_1); + BF(10, 13, -COS2_2); + BF(11, 12, -COS2_3); + + BF(16, 23, COS2_0); + BF(17, 22, COS2_1); + BF(18, 21, COS2_2); + BF(19, 20, COS2_3); + + BF(24, 31, -COS2_0); + BF(25, 30, -COS2_1); + BF(26, 29, -COS2_2); + BF(27, 28, -COS2_3); + + /* pass 4 */ + BF(0, 3, COS3_0); + BF(1, 2, COS3_1); + + BF(4, 7, -COS3_0); + BF(5, 6, -COS3_1); + + BF(8, 11, COS3_0); + BF(9, 10, COS3_1); + + BF(12, 15, -COS3_0); + BF(13, 14, -COS3_1); + + BF(16, 19, COS3_0); + BF(17, 18, COS3_1); + + BF(20, 23, -COS3_0); + BF(21, 22, -COS3_1); + + BF(24, 27, COS3_0); + BF(25, 26, COS3_1); + + BF(28, 31, -COS3_0); + BF(29, 30, -COS3_1); + + /* pass 5 */ + BF1(0, 1, 2, 3); + BF2(4, 5, 6, 7); + BF1(8, 9, 10, 11); + BF2(12, 13, 14, 15); + BF1(16, 17, 18, 19); + BF2(20, 21, 22, 23); + BF1(24, 25, 26, 27); + BF2(28, 29, 30, 31); + + /* pass 6 */ + + ADD( 8, 12); + ADD(12, 10); + ADD(10, 14); + ADD(14, 9); + ADD( 9, 13); + ADD(13, 11); + ADD(11, 15); + + out[ 0] = tab[0]; + out[16] = tab[1]; + out[ 8] = tab[2]; + out[24] = tab[3]; + out[ 4] = tab[4]; + out[20] = tab[5]; + out[12] = tab[6]; + out[28] = tab[7]; + out[ 2] = tab[8]; + out[18] = tab[9]; + out[10] = tab[10]; + out[26] = tab[11]; + out[ 6] = tab[12]; + out[22] = tab[13]; + out[14] = tab[14]; + out[30] = tab[15]; + + ADD(24, 28); + ADD(28, 26); + ADD(26, 30); + ADD(30, 25); + ADD(25, 29); + ADD(29, 27); + ADD(27, 31); + + out[ 1] = tab[16] + tab[24]; + out[17] = tab[17] + tab[25]; + out[ 9] = tab[18] + tab[26]; + out[25] = tab[19] + tab[27]; + out[ 5] = tab[20] + tab[28]; + out[21] = tab[21] + tab[29]; + out[13] = tab[22] + tab[30]; + out[29] = tab[23] + tab[31]; + out[ 3] = tab[24] + tab[20]; + out[19] = tab[25] + tab[21]; + out[11] = tab[26] + tab[22]; + out[27] = tab[27] + tab[23]; + out[ 7] = tab[28] + tab[18]; + out[23] = tab[29] + tab[19]; + out[15] = tab[30] + tab[17]; + out[31] = tab[31]; +} + +#define OUT_SHIFT (WFRAC_BITS + FRAC_BITS - 15) + +#if FRAC_BITS <= 15 + +static int round_sample(int sum) +{ + int sum1; + sum1 = (sum + (1 << (OUT_SHIFT - 1))) >> OUT_SHIFT; + if (sum1 < -32768) + sum1 = -32768; + else if (sum1 > 32767) + sum1 = 32767; + return sum1; +} + +/* signed 16x16 -> 32 multiply add accumulate */ +#define MACS(rt, ra, rb) rt += (ra) * (rb) + +/* signed 16x16 -> 32 multiply */ +#define MULS(ra, rb) ((ra) * (rb)) + +#else + +static int round_sample(int64_t sum) +{ + int sum1; + sum1 = (int)((sum + ((int64_t)(1) << (OUT_SHIFT - 1))) >> OUT_SHIFT); + if (sum1 < -32768) + sum1 = -32768; + else if (sum1 > 32767) + sum1 = 32767; + return sum1; +} + +#define MULS(ra, rb) MUL64(ra, rb) + +#endif + +#define SUM8(sum, op, w, p) \ +{ \ + sum op MULS((w)[0 * 64], p[0 * 64]);\ + sum op MULS((w)[1 * 64], p[1 * 64]);\ + sum op MULS((w)[2 * 64], p[2 * 64]);\ + sum op MULS((w)[3 * 64], p[3 * 64]);\ + sum op MULS((w)[4 * 64], p[4 * 64]);\ + sum op MULS((w)[5 * 64], p[5 * 64]);\ + sum op MULS((w)[6 * 64], p[6 * 64]);\ + sum op MULS((w)[7 * 64], p[7 * 64]);\ +} + +#define SUM8P2(sum1, op1, sum2, op2, w1, w2, p) \ +{ \ + int tmp;\ + tmp = p[0 * 64];\ + sum1 op1 MULS((w1)[0 * 64], tmp);\ + sum2 op2 MULS((w2)[0 * 64], tmp);\ + tmp = p[1 * 64];\ + sum1 op1 MULS((w1)[1 * 64], tmp);\ + sum2 op2 MULS((w2)[1 * 64], tmp);\ + tmp = p[2 * 64];\ + sum1 op1 MULS((w1)[2 * 64], tmp);\ + sum2 op2 MULS((w2)[2 * 64], tmp);\ + tmp = p[3 * 64];\ + sum1 op1 MULS((w1)[3 * 64], tmp);\ + sum2 op2 MULS((w2)[3 * 64], tmp);\ + tmp = p[4 * 64];\ + sum1 op1 MULS((w1)[4 * 64], tmp);\ + sum2 op2 MULS((w2)[4 * 64], tmp);\ + tmp = p[5 * 64];\ + sum1 op1 MULS((w1)[5 * 64], tmp);\ + sum2 op2 MULS((w2)[5 * 64], tmp);\ + tmp = p[6 * 64];\ + sum1 op1 MULS((w1)[6 * 64], tmp);\ + sum2 op2 MULS((w2)[6 * 64], tmp);\ + tmp = p[7 * 64];\ + sum1 op1 MULS((w1)[7 * 64], tmp);\ + sum2 op2 MULS((w2)[7 * 64], tmp);\ +} + + +/* 32 sub band synthesis filter. Input: 32 sub band samples, Output: + 32 samples. */ +/* XXX: optimize by avoiding ring buffer usage */ +static void synth_filter(MPADecodeContext *s1, + int ch, int16_t *samples, int incr, + int32_t sb_samples[SBLIMIT]) +{ + int32_t tmp[32]; + MPA_INT *synth_buf; + const MPA_INT *w, *w2, *p; + int j, offset, v; + int16_t *samples2; +#if FRAC_BITS <= 15 + int32_t sum, sum2; +#else + int64_t sum, sum2; +#endif + + dct32(tmp, sb_samples); + + offset = s1->synth_buf_offset[ch]; + synth_buf = s1->synth_buf[ch] + offset; + + for(j=0;j<32;j++) { + v = tmp[j]; +#if FRAC_BITS <= 15 + /* NOTE: can cause a loss in precision if very high amplitude + sound */ + if (v > 32767) + v = 32767; + else if (v < -32768) + v = -32768; +#endif + synth_buf[j] = v; + } + /* copy to avoid wrap */ + memcpy(synth_buf + 512, synth_buf, 32 * sizeof(MPA_INT)); + + samples2 = samples + 31 * incr; + w = window; + w2 = window + 31; + + sum = 0; + p = synth_buf + 16; + SUM8(sum, +=, w, p); + p = synth_buf + 48; + SUM8(sum, -=, w + 32, p); + *samples = round_sample(sum); + samples += incr; + w++; + + /* we calculate two samples at the same time to avoid one memory + access per two sample */ + for(j=1;j<16;j++) { + sum = 0; + sum2 = 0; + p = synth_buf + 16 + j; + SUM8P2(sum, +=, sum2, -=, w, w2, p); + p = synth_buf + 48 - j; + SUM8P2(sum, -=, sum2, -=, w + 32, w2 + 32, p); + + *samples = round_sample(sum); + samples += incr; + *samples2 = round_sample(sum2); + samples2 -= incr; + w++; + w2--; + } + + p = synth_buf + 32; + sum = 0; + SUM8(sum, -=, w + 32, p); + *samples = round_sample(sum); + + offset = (offset - 32) & 511; + s1->synth_buf_offset[ch] = offset; +} + +/* cos(pi*i/24) */ +#define C1 FIXR(0.99144486137381041114) +#define C3 FIXR(0.92387953251128675612) +#define C5 FIXR(0.79335334029123516458) +#define C7 FIXR(0.60876142900872063941) +#define C9 FIXR(0.38268343236508977173) +#define C11 FIXR(0.13052619222005159154) + +/* 12 points IMDCT. We compute it "by hand" by factorizing obvious + cases. */ +static void imdct12(int *out, int *in) +{ + int tmp; + int64_t in1_3, in1_9, in4_3, in4_9; + + in1_3 = MUL64(in[1], C3); + in1_9 = MUL64(in[1], C9); + in4_3 = MUL64(in[4], C3); + in4_9 = MUL64(in[4], C9); + + tmp = FRAC_RND(MUL64(in[0], C7) - in1_3 - MUL64(in[2], C11) + + MUL64(in[3], C1) - in4_9 - MUL64(in[5], C5)); + out[0] = tmp; + out[5] = -tmp; + tmp = FRAC_RND(MUL64(in[0] - in[3], C9) - in1_3 + + MUL64(in[2] + in[5], C3) - in4_9); + out[1] = tmp; + out[4] = -tmp; + tmp = FRAC_RND(MUL64(in[0], C11) - in1_9 + MUL64(in[2], C7) - + MUL64(in[3], C5) + in4_3 - MUL64(in[5], C1)); + out[2] = tmp; + out[3] = -tmp; + tmp = FRAC_RND(MUL64(-in[0], C5) + in1_9 + MUL64(in[2], C1) + + MUL64(in[3], C11) - in4_3 - MUL64(in[5], C7)); + out[6] = tmp; + out[11] = tmp; + tmp = FRAC_RND(MUL64(-in[0] + in[3], C3) - in1_9 + + MUL64(in[2] + in[5], C9) + in4_3); + out[7] = tmp; + out[10] = tmp; + tmp = FRAC_RND(-MUL64(in[0], C1) - in1_3 - MUL64(in[2], C5) - + MUL64(in[3], C7) - in4_9 - MUL64(in[5], C11)); + out[8] = tmp; + out[9] = tmp; +} + +#undef C1 +#undef C3 +#undef C5 +#undef C7 +#undef C9 +#undef C11 + +/* cos(pi*i/18) */ +#define C1 FIXR(0.98480775301220805936) +#define C2 FIXR(0.93969262078590838405) +#define C3 FIXR(0.86602540378443864676) +#define C4 FIXR(0.76604444311897803520) +#define C5 FIXR(0.64278760968653932632) +#define C6 FIXR(0.5) +#define C7 FIXR(0.34202014332566873304) +#define C8 FIXR(0.17364817766693034885) + +/* 0.5 / cos(pi*(2*i+1)/36) */ +static const int icos36[9] = { + FIXR(0.50190991877167369479), + FIXR(0.51763809020504152469), + FIXR(0.55168895948124587824), + FIXR(0.61038729438072803416), + FIXR(0.70710678118654752439), + FIXR(0.87172339781054900991), + FIXR(1.18310079157624925896), + FIXR(1.93185165257813657349), + FIXR(5.73685662283492756461), +}; + +static const int icos72[18] = { + /* 0.5 / cos(pi*(2*i+19)/72) */ + FIXR(0.74009361646113053152), + FIXR(0.82133981585229078570), + FIXR(0.93057949835178895673), + FIXR(1.08284028510010010928), + FIXR(1.30656296487637652785), + FIXR(1.66275476171152078719), + FIXR(2.31011315767264929558), + FIXR(3.83064878777019433457), + FIXR(11.46279281302667383546), + + /* 0.5 / cos(pi*(2*(i + 18) +19)/72) */ + FIXR(-0.67817085245462840086), + FIXR(-0.63023620700513223342), + FIXR(-0.59284452371708034528), + FIXR(-0.56369097343317117734), + FIXR(-0.54119610014619698439), + FIXR(-0.52426456257040533932), + FIXR(-0.51213975715725461845), + FIXR(-0.50431448029007636036), + FIXR(-0.50047634258165998492), +}; + +/* using Lee like decomposition followed by hand coded 9 points DCT */ +static void imdct36(int *out, int *in) +{ + int i, j, t0, t1, t2, t3, s0, s1, s2, s3; + int tmp[18], *tmp1, *in1; + int64_t in3_3, in6_6; + + for(i=17;i>=1;i--) + in[i] += in[i-1]; + for(i=17;i>=3;i-=2) + in[i] += in[i-2]; + + for(j=0;j<2;j++) { + tmp1 = tmp + j; + in1 = in + j; + + in3_3 = MUL64(in1[2*3], C3); + in6_6 = MUL64(in1[2*6], C6); + + tmp1[0] = FRAC_RND(MUL64(in1[2*1], C1) + in3_3 + + MUL64(in1[2*5], C5) + MUL64(in1[2*7], C7)); + tmp1[2] = in1[2*0] + FRAC_RND(MUL64(in1[2*2], C2) + + MUL64(in1[2*4], C4) + in6_6 + + MUL64(in1[2*8], C8)); + tmp1[4] = FRAC_RND(MUL64(in1[2*1] - in1[2*5] - in1[2*7], C3)); + tmp1[6] = FRAC_RND(MUL64(in1[2*2] - in1[2*4] - in1[2*8], C6)) - + in1[2*6] + in1[2*0]; + tmp1[8] = FRAC_RND(MUL64(in1[2*1], C5) - in3_3 - + MUL64(in1[2*5], C7) + MUL64(in1[2*7], C1)); + tmp1[10] = in1[2*0] + FRAC_RND(MUL64(-in1[2*2], C8) - + MUL64(in1[2*4], C2) + in6_6 + + MUL64(in1[2*8], C4)); + tmp1[12] = FRAC_RND(MUL64(in1[2*1], C7) - in3_3 + + MUL64(in1[2*5], C1) - + MUL64(in1[2*7], C5)); + tmp1[14] = in1[2*0] + FRAC_RND(MUL64(-in1[2*2], C4) + + MUL64(in1[2*4], C8) + in6_6 - + MUL64(in1[2*8], C2)); + tmp1[16] = in1[2*0] - in1[2*2] + in1[2*4] - in1[2*6] + in1[2*8]; + } + + i = 0; + for(j=0;j<4;j++) { + t0 = tmp[i]; + t1 = tmp[i + 2]; + s0 = t1 + t0; + s2 = t1 - t0; + + t2 = tmp[i + 1]; + t3 = tmp[i + 3]; + s1 = MULL(t3 + t2, icos36[j]); + s3 = MULL(t3 - t2, icos36[8 - j]); + + t0 = MULL(s0 + s1, icos72[9 + 8 - j]); + t1 = MULL(s0 - s1, icos72[8 - j]); + out[18 + 9 + j] = t0; + out[18 + 8 - j] = t0; + out[9 + j] = -t1; + out[8 - j] = t1; + + t0 = MULL(s2 + s3, icos72[9+j]); + t1 = MULL(s2 - s3, icos72[j]); + out[18 + 9 + (8 - j)] = t0; + out[18 + j] = t0; + out[9 + (8 - j)] = -t1; + out[j] = t1; + i += 4; + } + + s0 = tmp[16]; + s1 = MULL(tmp[17], icos36[4]); + t0 = MULL(s0 + s1, icos72[9 + 4]); + t1 = MULL(s0 - s1, icos72[4]); + out[18 + 9 + 4] = t0; + out[18 + 8 - 4] = t0; + out[9 + 4] = -t1; + out[8 - 4] = t1; +} + +/* fast header check for resync */ +static int check_header(uint32_t header) +{ + /* header */ + if ((header & 0xffe00000) != 0xffe00000) + return -1; + /* layer check */ + if (((header >> 17) & 3) == 0) + return -1; + /* bit rate */ + if (((header >> 12) & 0xf) == 0xf) + return -1; + /* frequency */ + if (((header >> 10) & 3) == 3) + return -1; + return 0; +} + +/* header + layer + bitrate + freq + lsf/mpeg25 */ +#define SAME_HEADER_MASK \ + (0xffe00000 | (3 << 17) | (0xf << 12) | (3 << 10) | (3 << 19)) + +/* header decoding. MUST check the header before because no + consistency check is done there. Return 1 if free format found and + that the frame size must be computed externally */ +static int decode_header(MPADecodeContext *s, uint32_t header) +{ + int sample_rate, frame_size, mpeg25, padding; + int sample_rate_index, bitrate_index; + if (header & (1<<20)) { + s->lsf = (header & (1<<19)) ? 0 : 1; + mpeg25 = 0; + } else { + s->lsf = 1; + mpeg25 = 1; + } + + s->layer = 4 - ((header >> 17) & 3); + /* extract frequency */ + sample_rate_index = (header >> 10) & 3; + sample_rate = mpa_freq_tab[sample_rate_index] >> (s->lsf + mpeg25); + sample_rate_index += 3 * (s->lsf + mpeg25); + s->sample_rate_index = sample_rate_index; + s->error_protection = ((header >> 16) & 1) ^ 1; + s->sample_rate = sample_rate; + + bitrate_index = (header >> 12) & 0xf; + padding = (header >> 9) & 1; + s->mode = (header >> 6) & 3; + s->mode_ext = (header >> 4) & 3; + + if (s->mode == MPA_MONO) + s->nb_channels = 1; + else + s->nb_channels = 2; + + if (bitrate_index != 0) { + frame_size = mpa_bitrate_tab[s->lsf][s->layer - 1][bitrate_index]; + s->bit_rate = frame_size * 1000; + switch(s->layer) { + case 1: + frame_size = (frame_size * 12000) / sample_rate; + frame_size = (frame_size + padding) * 4; + break; + case 2: + frame_size = (frame_size * 144000) / sample_rate; + frame_size += padding; + break; + default: + case 3: + frame_size = (frame_size * 144000) / (sample_rate << s->lsf); + frame_size += padding; + break; + } + s->frame_size = frame_size; + } else { + /* if no frame size computed, signal it */ + if (!s->free_format_frame_size) + return 1; + /* free format: compute bitrate and real frame size from the + frame size we extracted by reading the bitstream */ + s->frame_size = s->free_format_frame_size; + switch(s->layer) { + case 1: + s->frame_size += padding * 4; + s->bit_rate = (s->frame_size * sample_rate) / 48000; + break; + case 2: + s->frame_size += padding; + s->bit_rate = (s->frame_size * sample_rate) / 144000; + break; + default: + case 3: + s->frame_size += padding; + s->bit_rate = (s->frame_size * (sample_rate << s->lsf)) / 144000; + break; + } + } + +#if defined(DEBUG) + printf("layer%d, %d Hz, %d kbits/s, ", + s->layer, s->sample_rate, s->bit_rate); + if (s->nb_channels == 2) { + if (s->layer == 3) { + if (s->mode_ext & MODE_EXT_MS_STEREO) + printf("ms-"); + if (s->mode_ext & MODE_EXT_I_STEREO) + printf("i-"); + } + printf("stereo"); + } else { + printf("mono"); + } + printf("\n"); +#endif + return 0; +} + +/* return the number of decoded frames */ +static int mp_decode_layer1(MPADecodeContext *s) +{ + int bound, i, v, n, ch, j, mant; + uint8_t allocation[MPA_MAX_CHANNELS][SBLIMIT]; + uint8_t scale_factors[MPA_MAX_CHANNELS][SBLIMIT]; + + if (s->mode == MPA_JSTEREO) + bound = (s->mode_ext + 1) * 4; + else + bound = SBLIMIT; + + /* allocation bits */ + for(i=0;inb_channels;ch++) { + allocation[ch][i] = get_bits(&s->gb, 4); + } + } + for(i=bound;igb, 4); + } + + /* scale factors */ + for(i=0;inb_channels;ch++) { + if (allocation[ch][i]) + scale_factors[ch][i] = get_bits(&s->gb, 6); + } + } + for(i=bound;igb, 6); + scale_factors[1][i] = get_bits(&s->gb, 6); + } + } + + /* compute samples */ + for(j=0;j<12;j++) { + for(i=0;inb_channels;ch++) { + n = allocation[ch][i]; + if (n) { + mant = get_bits(&s->gb, n + 1); + v = l1_unscale(n, mant, scale_factors[ch][i]); + } else { + v = 0; + } + s->sb_samples[ch][j][i] = v; + } + } + for(i=bound;igb, n + 1); + v = l1_unscale(n, mant, scale_factors[0][i]); + s->sb_samples[0][j][i] = v; + v = l1_unscale(n, mant, scale_factors[1][i]); + s->sb_samples[1][j][i] = v; + } else { + s->sb_samples[0][j][i] = 0; + s->sb_samples[1][j][i] = 0; + } + } + } + return 12; +} + +/* bitrate is in kb/s */ +static int l2_select_table(int bitrate, int nb_channels, int freq, int lsf) +{ + int ch_bitrate, table; + + ch_bitrate = bitrate / nb_channels; + if (!lsf) { + if ((freq == 48000 && ch_bitrate >= 56) || + (ch_bitrate >= 56 && ch_bitrate <= 80)) + table = 0; + else if (freq != 48000 && ch_bitrate >= 96) + table = 1; + else if (freq != 32000 && ch_bitrate <= 48) + table = 2; + else + table = 3; + } else { + table = 4; + } + return table; +} + +static int mp_decode_layer2(MPADecodeContext *s) +{ + int sblimit; /* number of used subbands */ + const unsigned char *alloc_table; + int table, bit_alloc_bits, i, j, ch, bound, v; + unsigned char bit_alloc[MPA_MAX_CHANNELS][SBLIMIT]; + unsigned char scale_code[MPA_MAX_CHANNELS][SBLIMIT]; + unsigned char scale_factors[MPA_MAX_CHANNELS][SBLIMIT][3], *sf; + int scale, qindex, bits, steps, k, l, m, b; + + /* select decoding table */ + table = l2_select_table(s->bit_rate / 1000, s->nb_channels, + s->sample_rate, s->lsf); + sblimit = sblimit_table[table]; + alloc_table = alloc_tables[table]; + + if (s->mode == MPA_JSTEREO) + bound = (s->mode_ext + 1) * 4; + else + bound = sblimit; + +#ifdef DEBUG + printf("bound=%d sblimit=%d\n", bound, sblimit); +#endif + /* parse bit allocation */ + j = 0; + for(i=0;inb_channels;ch++) { + bit_alloc[ch][i] = get_bits(&s->gb, bit_alloc_bits); + } + j += 1 << bit_alloc_bits; + } + for(i=bound;igb, bit_alloc_bits); + bit_alloc[0][i] = v; + bit_alloc[1][i] = v; + j += 1 << bit_alloc_bits; + } + +#ifdef DEBUG + { + for(ch=0;chnb_channels;ch++) { + for(i=0;inb_channels;ch++) { + if (bit_alloc[ch][i]) + scale_code[ch][i] = get_bits(&s->gb, 2); + } + } + + /* scale factors */ + for(i=0;inb_channels;ch++) { + if (bit_alloc[ch][i]) { + sf = scale_factors[ch][i]; + switch(scale_code[ch][i]) { + default: + case 0: + sf[0] = get_bits(&s->gb, 6); + sf[1] = get_bits(&s->gb, 6); + sf[2] = get_bits(&s->gb, 6); + break; + case 2: + sf[0] = get_bits(&s->gb, 6); + sf[1] = sf[0]; + sf[2] = sf[0]; + break; + case 1: + sf[0] = get_bits(&s->gb, 6); + sf[2] = get_bits(&s->gb, 6); + sf[1] = sf[0]; + break; + case 3: + sf[0] = get_bits(&s->gb, 6); + sf[2] = get_bits(&s->gb, 6); + sf[1] = sf[2]; + break; + } + } + } + } + +#ifdef DEBUG + for(ch=0;chnb_channels;ch++) { + for(i=0;inb_channels;ch++) { + b = bit_alloc[ch][i]; + if (b) { + scale = scale_factors[ch][i][k]; + qindex = alloc_table[j+b]; + bits = quant_bits[qindex]; + if (bits < 0) { + /* 3 values at the same time */ + v = get_bits(&s->gb, -bits); + steps = quant_steps[qindex]; + s->sb_samples[ch][k * 12 + l + 0][i] = + l2_unscale_group(steps, v % steps, scale); + v = v / steps; + s->sb_samples[ch][k * 12 + l + 1][i] = + l2_unscale_group(steps, v % steps, scale); + v = v / steps; + s->sb_samples[ch][k * 12 + l + 2][i] = + l2_unscale_group(steps, v, scale); + } else { + for(m=0;m<3;m++) { + v = get_bits(&s->gb, bits); + v = l1_unscale(bits - 1, v, scale); + s->sb_samples[ch][k * 12 + l + m][i] = v; + } + } + } else { + s->sb_samples[ch][k * 12 + l + 0][i] = 0; + s->sb_samples[ch][k * 12 + l + 1][i] = 0; + s->sb_samples[ch][k * 12 + l + 2][i] = 0; + } + } + /* next subband in alloc table */ + j += 1 << bit_alloc_bits; + } + /* XXX: find a way to avoid this duplication of code */ + for(i=bound;igb, -bits); + steps = quant_steps[qindex]; + mant = v % steps; + v = v / steps; + s->sb_samples[0][k * 12 + l + 0][i] = + l2_unscale_group(steps, mant, scale0); + s->sb_samples[1][k * 12 + l + 0][i] = + l2_unscale_group(steps, mant, scale1); + mant = v % steps; + v = v / steps; + s->sb_samples[0][k * 12 + l + 1][i] = + l2_unscale_group(steps, mant, scale0); + s->sb_samples[1][k * 12 + l + 1][i] = + l2_unscale_group(steps, mant, scale1); + s->sb_samples[0][k * 12 + l + 2][i] = + l2_unscale_group(steps, v, scale0); + s->sb_samples[1][k * 12 + l + 2][i] = + l2_unscale_group(steps, v, scale1); + } else { + for(m=0;m<3;m++) { + mant = get_bits(&s->gb, bits); + s->sb_samples[0][k * 12 + l + m][i] = + l1_unscale(bits - 1, mant, scale0); + s->sb_samples[1][k * 12 + l + m][i] = + l1_unscale(bits - 1, mant, scale1); + } + } + } else { + s->sb_samples[0][k * 12 + l + 0][i] = 0; + s->sb_samples[0][k * 12 + l + 1][i] = 0; + s->sb_samples[0][k * 12 + l + 2][i] = 0; + s->sb_samples[1][k * 12 + l + 0][i] = 0; + s->sb_samples[1][k * 12 + l + 1][i] = 0; + s->sb_samples[1][k * 12 + l + 2][i] = 0; + } + /* next subband in alloc table */ + j += 1 << bit_alloc_bits; + } + /* fill remaining samples to zero */ + for(i=sblimit;inb_channels;ch++) { + s->sb_samples[ch][k * 12 + l + 0][i] = 0; + s->sb_samples[ch][k * 12 + l + 1][i] = 0; + s->sb_samples[ch][k * 12 + l + 2][i] = 0; + } + } + } + } + return 3 * 12; +} + +/* + * Seek back in the stream for backstep bytes (at most 511 bytes) + */ +static void seek_to_maindata(MPADecodeContext *s, unsigned int backstep) +{ + uint8_t *ptr; + + /* compute current position in stream */ + ptr = (uint8_t *)(s->gb.buffer + (get_bits_count(&s->gb)>>3)); + + /* copy old data before current one */ + ptr -= backstep; + memcpy(ptr, s->inbuf1[s->inbuf_index ^ 1] + + BACKSTEP_SIZE + s->old_frame_size - backstep, backstep); + /* init get bits again */ + init_get_bits(&s->gb, ptr, (s->frame_size + backstep)*8); + + /* prepare next buffer */ + s->inbuf_index ^= 1; + s->inbuf = &s->inbuf1[s->inbuf_index][BACKSTEP_SIZE]; + s->old_frame_size = s->frame_size; +} + +static void lsf_sf_expand(int *slen, + int sf, int n1, int n2, int n3) +{ + if (n3) { + slen[3] = sf % n3; + sf /= n3; + } else { + slen[3] = 0; + } + if (n2) { + slen[2] = sf % n2; + sf /= n2; + } else { + slen[2] = 0; + } + slen[1] = sf % n1; + sf /= n1; + slen[0] = sf; +} + +static void exponents_from_scale_factors(MPADecodeContext *s, + GranuleDef *g, + int16_t *exponents) +{ + const uint8_t *bstab, *pretab; + int len, i, j, k, l, v0, shift, gain, gains[3]; + int16_t *exp_ptr; + + exp_ptr = exponents; + gain = g->global_gain - 210; + shift = g->scalefac_scale + 1; + + bstab = band_size_long[s->sample_rate_index]; + pretab = mpa_pretab[g->preflag]; + for(i=0;ilong_end;i++) { + v0 = gain - ((g->scale_factors[i] + pretab[i]) << shift); + len = bstab[i]; + for(j=len;j>0;j--) + *exp_ptr++ = v0; + } + + if (g->short_start < 13) { + bstab = band_size_short[s->sample_rate_index]; + gains[0] = gain - (g->subblock_gain[0] << 3); + gains[1] = gain - (g->subblock_gain[1] << 3); + gains[2] = gain - (g->subblock_gain[2] << 3); + k = g->long_end; + for(i=g->short_start;i<13;i++) { + len = bstab[i]; + for(l=0;l<3;l++) { + v0 = gains[l] - (g->scale_factors[k++] << shift); + for(j=len;j>0;j--) + *exp_ptr++ = v0; + } + } + } +} + +/* handle n = 0 too */ +static int get_bitsz(GetBitContext *s, int n) +{ + if (n == 0) + return 0; + else + return get_bits(s, n); +} + +static int huffman_decode(MPADecodeContext *s, GranuleDef *g, + int16_t *exponents, int end_pos) +{ + int s_index; + int linbits, code, x, y, l, v, i, j, k, pos; + GetBitContext last_gb; + VLC *vlc; + uint8_t *code_table; + + /* low frequencies (called big values) */ + s_index = 0; + for(i=0;i<3;i++) { + j = g->region_size[i]; + if (j == 0) + continue; + /* select vlc table */ + k = g->table_select[i]; + l = mpa_huff_data[k][0]; + linbits = mpa_huff_data[k][1]; + vlc = &huff_vlc[l]; + code_table = huff_code_table[l]; + + /* read huffcode and compute each couple */ + for(;j>0;j--) { + if (get_bits_count(&s->gb) >= end_pos) + break; + if (code_table) { + code = get_vlc(&s->gb, vlc); + if (code < 0) + return -1; + y = code_table[code]; + x = y >> 4; + y = y & 0x0f; + } else { + x = 0; + y = 0; + } +#ifdef DEBUG + printf("region=%d n=%d x=%d y=%d exp=%d\n", + i, g->region_size[i] - j, x, y, exponents[s_index]); +#endif + if (x) { + if (x == 15) + x += get_bitsz(&s->gb, linbits); + v = l3_unscale(x, exponents[s_index]); + if (get_bits(&s->gb, 1)) + v = -v; + } else { + v = 0; + } + g->sb_hybrid[s_index++] = v; + if (y) { + if (y == 15) + y += get_bitsz(&s->gb, linbits); + v = l3_unscale(y, exponents[s_index]); + if (get_bits(&s->gb, 1)) + v = -v; + } else { + v = 0; + } + g->sb_hybrid[s_index++] = v; + } + } + + /* high frequencies */ + vlc = &huff_quad_vlc[g->count1table_select]; + last_gb.buffer = NULL; + while (s_index <= 572) { + pos = get_bits_count(&s->gb); + if (pos >= end_pos) { + if (pos > end_pos && last_gb.buffer != NULL) { + /* some encoders generate an incorrect size for this + part. We must go back into the data */ + s_index -= 4; + s->gb = last_gb; + } + break; + } + last_gb= s->gb; + + code = get_vlc(&s->gb, vlc); +#ifdef DEBUG + printf("t=%d code=%d\n", g->count1table_select, code); +#endif + if (code < 0) + return -1; + for(i=0;i<4;i++) { + if (code & (8 >> i)) { + /* non zero value. Could use a hand coded function for + 'one' value */ + v = l3_unscale(1, exponents[s_index]); + if(get_bits(&s->gb, 1)) + v = -v; + } else { + v = 0; + } + g->sb_hybrid[s_index++] = v; + } + } + while (s_index < 576) + g->sb_hybrid[s_index++] = 0; + return 0; +} + +/* Reorder short blocks from bitstream order to interleaved order. It + would be faster to do it in parsing, but the code would be far more + complicated */ +static void reorder_block(MPADecodeContext *s, GranuleDef *g) +{ + int i, j, k, len; + int32_t *ptr, *dst, *ptr1; + int32_t tmp[576]; + + if (g->block_type != 2) + return; + + if (g->switch_point) { + if (s->sample_rate_index != 8) { + ptr = g->sb_hybrid + 36; + } else { + ptr = g->sb_hybrid + 48; + } + } else { + ptr = g->sb_hybrid; + } + + for(i=g->short_start;i<13;i++) { + len = band_size_short[s->sample_rate_index][i]; + ptr1 = ptr; + for(k=0;k<3;k++) { + dst = tmp + k; + for(j=len;j>0;j--) { + *dst = *ptr++; + dst += 3; + } + } + memcpy(ptr1, tmp, len * 3 * sizeof(int32_t)); + } +} + +#define ISQRT2 FIXR(0.70710678118654752440) + +static void compute_stereo(MPADecodeContext *s, + GranuleDef *g0, GranuleDef *g1) +{ + int i, j, k, l; + int32_t v1, v2; + int sf_max, tmp0, tmp1, sf, len, non_zero_found; + int32_t (*is_tab)[16]; + int32_t *tab0, *tab1; + int non_zero_found_short[3]; + + /* intensity stereo */ + if (s->mode_ext & MODE_EXT_I_STEREO) { + if (!s->lsf) { + is_tab = is_table; + sf_max = 7; + } else { + is_tab = is_table_lsf[g1->scalefac_compress & 1]; + sf_max = 16; + } + + tab0 = g0->sb_hybrid + 576; + tab1 = g1->sb_hybrid + 576; + + non_zero_found_short[0] = 0; + non_zero_found_short[1] = 0; + non_zero_found_short[2] = 0; + k = (13 - g1->short_start) * 3 + g1->long_end - 3; + for(i = 12;i >= g1->short_start;i--) { + /* for last band, use previous scale factor */ + if (i != 11) + k -= 3; + len = band_size_short[s->sample_rate_index][i]; + for(l=2;l>=0;l--) { + tab0 -= len; + tab1 -= len; + if (!non_zero_found_short[l]) { + /* test if non zero band. if so, stop doing i-stereo */ + for(j=0;jscale_factors[k + l]; + if (sf >= sf_max) + goto found1; + + v1 = is_tab[0][sf]; + v2 = is_tab[1][sf]; + for(j=0;jmode_ext & MODE_EXT_MS_STEREO) { + /* lower part of the spectrum : do ms stereo + if enabled */ + for(j=0;jlong_end - 1;i >= 0;i--) { + len = band_size_long[s->sample_rate_index][i]; + tab0 -= len; + tab1 -= len; + /* test if non zero band. if so, stop doing i-stereo */ + if (!non_zero_found) { + for(j=0;jscale_factors[k]; + if (sf >= sf_max) + goto found2; + v1 = is_tab[0][sf]; + v2 = is_tab[1][sf]; + for(j=0;jmode_ext & MODE_EXT_MS_STEREO) { + /* lower part of the spectrum : do ms stereo + if enabled */ + for(j=0;jmode_ext & MODE_EXT_MS_STEREO) { + /* ms stereo ONLY */ + /* NOTE: the 1/sqrt(2) normalization factor is included in the + global gain */ + tab0 = g0->sb_hybrid; + tab1 = g1->sb_hybrid; + for(i=0;i<576;i++) { + tmp0 = tab0[i]; + tmp1 = tab1[i]; + tab0[i] = tmp0 + tmp1; + tab1[i] = tmp0 - tmp1; + } + } +} + +static void compute_antialias(MPADecodeContext *s, + GranuleDef *g) +{ + int32_t *ptr, *p0, *p1, *csa; + int n, tmp0, tmp1, i, j; + + /* we antialias only "long" bands */ + if (g->block_type == 2) { + if (!g->switch_point) + return; + /* XXX: check this for 8000Hz case */ + n = 1; + } else { + n = SBLIMIT - 1; + } + + ptr = g->sb_hybrid + 18; + for(i = n;i > 0;i--) { + p0 = ptr - 1; + p1 = ptr; + csa = &csa_table[0][0]; + for(j=0;j<8;j++) { + tmp0 = *p0; + tmp1 = *p1; + *p0 = FRAC_RND(MUL64(tmp0, csa[0]) - MUL64(tmp1, csa[1])); + *p1 = FRAC_RND(MUL64(tmp0, csa[1]) + MUL64(tmp1, csa[0])); + p0--; + p1++; + csa += 2; + } + ptr += 18; + } +} + +static void compute_imdct(MPADecodeContext *s, + GranuleDef *g, + int32_t *sb_samples, + int32_t *mdct_buf) +{ + int32_t *ptr, *win, *win1, *buf, *buf2, *out_ptr, *ptr1; + int32_t in[6]; + int32_t out[36]; + int32_t out2[12]; + int i, j, k, mdct_long_end, v, sblimit; + + /* find last non zero block */ + ptr = g->sb_hybrid + 576; + ptr1 = g->sb_hybrid + 2 * 18; + while (ptr >= ptr1) { + ptr -= 6; + v = ptr[0] | ptr[1] | ptr[2] | ptr[3] | ptr[4] | ptr[5]; + if (v != 0) + break; + } + sblimit = ((ptr - g->sb_hybrid) / 18) + 1; + + if (g->block_type == 2) { + /* XXX: check for 8000 Hz */ + if (g->switch_point) + mdct_long_end = 2; + else + mdct_long_end = 0; + } else { + mdct_long_end = sblimit; + } + + buf = mdct_buf; + ptr = g->sb_hybrid; + for(j=0;jswitch_point && j < 2) + win1 = mdct_win[0]; + else + win1 = mdct_win[g->block_type]; + /* select frequency inversion */ + win = win1 + ((4 * 36) & -(j & 1)); + for(i=0;i<18;i++) { + *out_ptr = MULL(out[i], win[i]) + buf[i]; + buf[i] = MULL(out[i + 18], win[i + 18]); + out_ptr += SBLIMIT; + } + ptr += 18; + buf += 18; + } + for(j=mdct_long_end;jlsf) { + main_data_begin = get_bits(&s->gb, 8); + if (s->nb_channels == 2) + private_bits = get_bits(&s->gb, 2); + else + private_bits = get_bits(&s->gb, 1); + nb_granules = 1; + } else { + main_data_begin = get_bits(&s->gb, 9); + if (s->nb_channels == 2) + private_bits = get_bits(&s->gb, 3); + else + private_bits = get_bits(&s->gb, 5); + nb_granules = 2; + for(ch=0;chnb_channels;ch++) { + granules[ch][0].scfsi = 0; /* all scale factors are transmitted */ + granules[ch][1].scfsi = get_bits(&s->gb, 4); + } + } + + for(gr=0;grnb_channels;ch++) { +#ifdef DEBUG + printf("gr=%d ch=%d: side_info\n", gr, ch); +#endif + g = &granules[ch][gr]; + g->part2_3_length = get_bits(&s->gb, 12); + g->big_values = get_bits(&s->gb, 9); + g->global_gain = get_bits(&s->gb, 8); + /* if MS stereo only is selected, we precompute the + 1/sqrt(2) renormalization factor */ + if ((s->mode_ext & (MODE_EXT_MS_STEREO | MODE_EXT_I_STEREO)) == + MODE_EXT_MS_STEREO) + g->global_gain -= 2; + if (s->lsf) + g->scalefac_compress = get_bits(&s->gb, 9); + else + g->scalefac_compress = get_bits(&s->gb, 4); + blocksplit_flag = get_bits(&s->gb, 1); + if (blocksplit_flag) { + g->block_type = get_bits(&s->gb, 2); + if (g->block_type == 0) + return -1; + g->switch_point = get_bits(&s->gb, 1); + for(i=0;i<2;i++) + g->table_select[i] = get_bits(&s->gb, 5); + for(i=0;i<3;i++) + g->subblock_gain[i] = get_bits(&s->gb, 3); + /* compute huffman coded region sizes */ + if (g->block_type == 2) + g->region_size[0] = (36 / 2); + else { + if (s->sample_rate_index <= 2) + g->region_size[0] = (36 / 2); + else if (s->sample_rate_index != 8) + g->region_size[0] = (54 / 2); + else + g->region_size[0] = (108 / 2); + } + g->region_size[1] = (576 / 2); + } else { + int region_address1, region_address2, l; + g->block_type = 0; + g->switch_point = 0; + for(i=0;i<3;i++) + g->table_select[i] = get_bits(&s->gb, 5); + /* compute huffman coded region sizes */ + region_address1 = get_bits(&s->gb, 4); + region_address2 = get_bits(&s->gb, 3); +#ifdef DEBUG + printf("region1=%d region2=%d\n", + region_address1, region_address2); +#endif + g->region_size[0] = + band_index_long[s->sample_rate_index][region_address1 + 1] >> 1; + l = region_address1 + region_address2 + 2; + /* should not overflow */ + if (l > 22) + l = 22; + g->region_size[1] = + band_index_long[s->sample_rate_index][l] >> 1; + } + /* convert region offsets to region sizes and truncate + size to big_values */ + g->region_size[2] = (576 / 2); + j = 0; + for(i=0;i<3;i++) { + k = g->region_size[i]; + if (k > g->big_values) + k = g->big_values; + g->region_size[i] = k - j; + j = k; + } + + /* compute band indexes */ + if (g->block_type == 2) { + if (g->switch_point) { + /* if switched mode, we handle the 36 first samples as + long blocks. For 8000Hz, we handle the 48 first + exponents as long blocks (XXX: check this!) */ + if (s->sample_rate_index <= 2) + g->long_end = 8; + else if (s->sample_rate_index != 8) + g->long_end = 6; + else + g->long_end = 4; /* 8000 Hz */ + + if (s->sample_rate_index != 8) + g->short_start = 3; + else + g->short_start = 2; + } else { + g->long_end = 0; + g->short_start = 0; + } + } else { + g->short_start = 13; + g->long_end = 22; + } + + g->preflag = 0; + if (!s->lsf) + g->preflag = get_bits(&s->gb, 1); + g->scalefac_scale = get_bits(&s->gb, 1); + g->count1table_select = get_bits(&s->gb, 1); +#ifdef DEBUG + printf("block_type=%d switch_point=%d\n", + g->block_type, g->switch_point); +#endif + } + } + + /* now we get bits from the main_data_begin offset */ +#ifdef DEBUG + printf("seekback: %d\n", main_data_begin); +#endif + seek_to_maindata(s, main_data_begin); + + for(gr=0;grnb_channels;ch++) { + g = &granules[ch][gr]; + + bits_pos = get_bits_count(&s->gb); + + if (!s->lsf) { + uint8_t *sc; + int slen, slen1, slen2; + + /* MPEG1 scale factors */ + slen1 = slen_table[0][g->scalefac_compress]; + slen2 = slen_table[1][g->scalefac_compress]; +#ifdef DEBUG + printf("slen1=%d slen2=%d\n", slen1, slen2); +#endif + if (g->block_type == 2) { + n = g->switch_point ? 17 : 18; + j = 0; + for(i=0;iscale_factors[j++] = get_bitsz(&s->gb, slen1); + for(i=0;i<18;i++) + g->scale_factors[j++] = get_bitsz(&s->gb, slen2); + for(i=0;i<3;i++) + g->scale_factors[j++] = 0; + } else { + sc = granules[ch][0].scale_factors; + j = 0; + for(k=0;k<4;k++) { + n = (k == 0 ? 6 : 5); + if ((g->scfsi & (0x8 >> k)) == 0) { + slen = (k < 2) ? slen1 : slen2; + for(i=0;iscale_factors[j++] = get_bitsz(&s->gb, slen); + } else { + /* simply copy from last granule */ + for(i=0;iscale_factors[j] = sc[j]; + j++; + } + } + } + g->scale_factors[j++] = 0; + } +#if defined(DEBUG) + { + printf("scfsi=%x gr=%d ch=%d scale_factors:\n", + g->scfsi, gr, ch); + for(i=0;iscale_factors[i]); + printf("\n"); + } +#endif + } else { + int tindex, tindex2, slen[4], sl, sf; + + /* LSF scale factors */ + if (g->block_type == 2) { + tindex = g->switch_point ? 2 : 1; + } else { + tindex = 0; + } + sf = g->scalefac_compress; + if ((s->mode_ext & MODE_EXT_I_STEREO) && ch == 1) { + /* intensity stereo case */ + sf >>= 1; + if (sf < 180) { + lsf_sf_expand(slen, sf, 6, 6, 0); + tindex2 = 3; + } else if (sf < 244) { + lsf_sf_expand(slen, sf - 180, 4, 4, 0); + tindex2 = 4; + } else { + lsf_sf_expand(slen, sf - 244, 3, 0, 0); + tindex2 = 5; + } + } else { + /* normal case */ + if (sf < 400) { + lsf_sf_expand(slen, sf, 5, 4, 4); + tindex2 = 0; + } else if (sf < 500) { + lsf_sf_expand(slen, sf - 400, 5, 4, 0); + tindex2 = 1; + } else { + lsf_sf_expand(slen, sf - 500, 3, 0, 0); + tindex2 = 2; + g->preflag = 1; + } + } + + j = 0; + for(k=0;k<4;k++) { + n = lsf_nsf_table[tindex2][tindex][k]; + sl = slen[k]; + for(i=0;iscale_factors[j++] = get_bitsz(&s->gb, sl); + } + /* XXX: should compute exact size */ + for(;j<40;j++) + g->scale_factors[j] = 0; +#if defined(DEBUG) + { + printf("gr=%d ch=%d scale_factors:\n", + gr, ch); + for(i=0;i<40;i++) + printf(" %d", g->scale_factors[i]); + printf("\n"); + } +#endif + } + + exponents_from_scale_factors(s, g, exponents); + + /* read Huffman coded residue */ + if (huffman_decode(s, g, exponents, + bits_pos + g->part2_3_length) < 0) + return -1; + + /* skip extension bits */ + bits_left = g->part2_3_length - (get_bits_count(&s->gb) - bits_pos); + if (bits_left < 0) { +#ifdef DEBUG + printf("bits_left=%d\n", bits_left); +#endif + return -1; + } + while (bits_left >= 16) { + skip_bits(&s->gb, 16); + bits_left -= 16; + } + if (bits_left > 0) + skip_bits(&s->gb, bits_left); + } /* ch */ + + if (s->nb_channels == 2) + compute_stereo(s, &granules[0][gr], &granules[1][gr]); + + for(ch=0;chnb_channels;ch++) { + g = &granules[ch][gr]; + + reorder_block(s, g); + compute_antialias(s, g); + compute_imdct(s, g, &s->sb_samples[ch][18 * gr][0], s->mdct_buf[ch]); + } + } /* gr */ + return nb_granules * 18; +} + +static int mp_decode_frame(MPADecodeContext *s, + int16_t *samples) +{ + int i, nb_frames, ch; + int16_t *samples_ptr; + + init_get_bits(&s->gb, s->inbuf + HEADER_SIZE, + (s->inbuf_ptr - s->inbuf - HEADER_SIZE)*8); + + /* skip error protection field */ + if (s->error_protection) + get_bits(&s->gb, 16); + +#ifdef DEBUG + printf("frame %d:\n", s->frame_count); +#endif + switch(s->layer) { + case 1: + nb_frames = mp_decode_layer1(s); + break; + case 2: + nb_frames = mp_decode_layer2(s); + break; + case 3: + default: + nb_frames = mp_decode_layer3(s); + break; + } +#if defined(DEBUG) + for(i=0;inb_channels;ch++) { + int j; + printf("%d-%d:", i, ch); + for(j=0;jsb_samples[ch][i][j] / FRAC_ONE); + printf("\n"); + } + } +#endif + /* apply the synthesis filter */ + for(ch=0;chnb_channels;ch++) { + samples_ptr = samples + ch; + for(i=0;inb_channels, + s->sb_samples[ch][i]); + samples_ptr += 32 * s->nb_channels; + } + } +#ifdef DEBUG + s->frame_count++; +#endif + return nb_frames * 32 * sizeof(short) * s->nb_channels; +} + +int mpaudec_decode_frame(MPAuDecContext * mpctx, + void *data, int *data_size, + const uint8_t * buf, int buf_size) +{ + MPADecodeContext *s; + const uint8_t *buf_ptr = buf; + int out_size = 0; + int16_t *out_samples = data; + assert(mpctx != NULL); + assert(mpctx->priv_data != NULL); + s = mpctx->priv_data; + + while (buf_size > 0 && out_size == 0) { + uint32_t header; + uint32_t free_format_next_header = 0; + int len = s->inbuf_ptr - s->inbuf; + if (s->frame_size == 0) { + /* no header seen : find one. We need at least HEADER_SIZE + bytes to parse it */ + len = HEADER_SIZE - len; + if (len > buf_size) + len = buf_size; + if (len > 0) { + memcpy(s->inbuf_ptr, buf_ptr, len); + buf_ptr += len; + buf_size -= len; + s->inbuf_ptr += len; + } + if ((s->inbuf_ptr - s->inbuf) >= HEADER_SIZE) { + header = (s->inbuf[0] << 24) | (s->inbuf[1] << 16) | + (s->inbuf[2] << 8) | s->inbuf[3]; + + if (check_header(header) < 0) { + /* no sync found : move by one byte (inefficient, but simple!) */ + memmove(s->inbuf, s->inbuf + 1, s->inbuf_ptr - s->inbuf - 1); + s->inbuf_ptr--; +#ifdef DEBUG + printf("skip %x\n", header); +#endif + /* reset free format frame size to give a chance + to get a new bitrate */ + s->free_format_frame_size = 0; + } else { + if (decode_header(s, header) == 1) { + /* free format: prepare to compute frame size */ + s->frame_size = -1; + } + /* update codec info */ + mpctx->sample_rate = s->sample_rate; + mpctx->channels = s->nb_channels; + mpctx->bit_rate = s->bit_rate; + mpctx->layer = s->layer; + switch(s->layer) { + case 1: + mpctx->frame_size = 384; + break; + case 2: + mpctx->frame_size = 1152; + break; + case 3: + if (s->lsf) + mpctx->frame_size = 576; + else + mpctx->frame_size = 1152; + break; + } + } + } + } else if (s->frame_size == -1) { + /* free format : find next sync to compute frame size */ + len = MPA_MAX_CODED_FRAME_SIZE - len; + if (len > buf_size) + len = buf_size; + if (len == 0) { + /* frame too long: resync */ + s->frame_size = 0; + memmove(s->inbuf, s->inbuf + 1, s->inbuf_ptr - s->inbuf - 1); + s->inbuf_ptr--; + } else { + uint8_t *p, *pend; + uint32_t header1; + int padding; + + memcpy(s->inbuf_ptr, buf_ptr, len); + /* check for header */ + p = s->inbuf_ptr - 3; + pend = s->inbuf_ptr + len - 4; + while (p <= pend && free_format_next_header == 0) { + header = (p[0] << 24) | (p[1] << 16) | + (p[2] << 8) | p[3]; + header1 = (s->inbuf[0] << 24) | (s->inbuf[1] << 16) | + (s->inbuf[2] << 8) | s->inbuf[3]; + /* check with high probability that we have a + valid header */ + if ((header & SAME_HEADER_MASK) == + (header1 & SAME_HEADER_MASK)) { + /* header found: update pointers */ + len = (p + 4) - s->inbuf_ptr; + buf_ptr += len; + buf_size -= len; + s->inbuf_ptr = p; + free_format_next_header = header; + /* compute frame size */ + s->free_format_frame_size = s->inbuf_ptr - s->inbuf; + padding = (header1 >> 9) & 1; + if (s->layer == 1) + s->free_format_frame_size -= padding * 4; + else + s->free_format_frame_size -= padding; +#ifdef DEBUG + printf("free frame size=%d padding=%d\n", + s->free_format_frame_size, padding); +#endif + decode_header(s, header1); + } else + p++; + } + if (free_format_next_header == 0) { + /* not found: simply increase pointers */ + buf_ptr += len; + s->inbuf_ptr += len; + buf_size -= len; + } + } + } else if (len < s->frame_size) { + if (s->frame_size > MPA_MAX_CODED_FRAME_SIZE) + s->frame_size = MPA_MAX_CODED_FRAME_SIZE; + len = s->frame_size - len; + if (len > buf_size) + len = buf_size; + memcpy(s->inbuf_ptr, buf_ptr, len); + buf_ptr += len; + s->inbuf_ptr += len; + buf_size -= len; + } + if (s->frame_size > 0 && + (s->inbuf_ptr - s->inbuf) >= s->frame_size) { + mpctx->coded_frame_size = s->frame_size; + if (mpctx->parse_only) { + /* simply return the frame data */ + *(uint8_t **)data = s->inbuf; + out_size = s->inbuf_ptr - s->inbuf; + } else { + out_size = mp_decode_frame(s, out_samples); + } + if (free_format_next_header != 0) { + s->inbuf[0] = free_format_next_header >> 24; + s->inbuf[1] = free_format_next_header >> 16; + s->inbuf[2] = free_format_next_header >> 8; + s->inbuf[3] = free_format_next_header; + s->inbuf_ptr = s->inbuf + 4; + } else + s->inbuf_ptr = s->inbuf; + s->frame_size = 0; + } + } + *data_size = out_size; + return buf_ptr - buf; +} + +void mpaudec_clear(MPAuDecContext *mpctx) +{ + assert(mpctx != NULL); + free(mpctx->priv_data); + memset(mpctx, 0, sizeof(MPAuDecContext)); +} diff --git a/src/Client/GUI/decoder/mpaudec.h b/src/Client/GUI/decoder/mpaudec.h new file mode 100644 index 0000000..06205ba --- /dev/null +++ b/src/Client/GUI/decoder/mpaudec.h @@ -0,0 +1,34 @@ +/* Portions based on avcodec.h from libavcodec. */ + +#ifndef MPAUDEC_H +#define MPAUDEC_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* in bytes */ +#define MPAUDEC_MAX_AUDIO_FRAME_SIZE 4608 + +typedef struct MPAuDecContext { + int bit_rate; + int layer; + int sample_rate; + int channels; + int frame_size; + void *priv_data; + int parse_only; + int coded_frame_size; +} MPAuDecContext; + +int mpaudec_init(MPAuDecContext *mpctx); +int mpaudec_decode_frame(MPAuDecContext * mpctx, + void *data, int *data_size, + const unsigned char * buf, int buf_size); +void mpaudec_clear(MPAuDecContext *mpctx); + +#ifdef __cplusplus +} +#endif + +#endif /* MPAUDEC_H */ diff --git a/src/Client/GUI/decoder/mpaudectab.h b/src/Client/GUI/decoder/mpaudectab.h new file mode 100644 index 0000000..7db90e1 --- /dev/null +++ b/src/Client/GUI/decoder/mpaudectab.h @@ -0,0 +1,772 @@ +/* Modified slightly by Matt Campbell for the + stand-alone mpaudec library. Based on mpegaudiodectab.h from libavcodec. */ + +static const uint16_t mpa_bitrate_tab[2][3][15] = { + { {0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448 }, + {0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384 }, + {0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320 } }, + { {0, 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160}, + {0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160} + } +}; + +static const uint16_t mpa_freq_tab[3] = { 44100, 48000, 32000 }; + +/*******************************************************/ +/* half mpeg encoding window (full precision) */ +static const int32_t mpa_enwindow[257] = { + 0, -1, -1, -1, -1, -1, -1, -2, + -2, -2, -2, -3, -3, -4, -4, -5, + -5, -6, -7, -7, -8, -9, -10, -11, + -13, -14, -16, -17, -19, -21, -24, -26, + -29, -31, -35, -38, -41, -45, -49, -53, + -58, -63, -68, -73, -79, -85, -91, -97, + -104, -111, -117, -125, -132, -139, -147, -154, + -161, -169, -176, -183, -190, -196, -202, -208, + 213, 218, 222, 225, 227, 228, 228, 227, + 224, 221, 215, 208, 200, 189, 177, 163, + 146, 127, 106, 83, 57, 29, -2, -36, + -72, -111, -153, -197, -244, -294, -347, -401, + -459, -519, -581, -645, -711, -779, -848, -919, + -991, -1064, -1137, -1210, -1283, -1356, -1428, -1498, + -1567, -1634, -1698, -1759, -1817, -1870, -1919, -1962, + -2001, -2032, -2057, -2075, -2085, -2087, -2080, -2063, + 2037, 2000, 1952, 1893, 1822, 1739, 1644, 1535, + 1414, 1280, 1131, 970, 794, 605, 402, 185, + -45, -288, -545, -814, -1095, -1388, -1692, -2006, + -2330, -2663, -3004, -3351, -3705, -4063, -4425, -4788, + -5153, -5517, -5879, -6237, -6589, -6935, -7271, -7597, + -7910, -8209, -8491, -8755, -8998, -9219, -9416, -9585, + -9727, -9838, -9916, -9959, -9966, -9935, -9863, -9750, + -9592, -9389, -9139, -8840, -8492, -8092, -7640, -7134, + 6574, 5959, 5288, 4561, 3776, 2935, 2037, 1082, + 70, -998, -2122, -3300, -4533, -5818, -7154, -8540, + -9975,-11455,-12980,-14548,-16155,-17799,-19478,-21189, +-22929,-24694,-26482,-28289,-30112,-31947,-33791,-35640, +-37489,-39336,-41176,-43006,-44821,-46617,-48390,-50137, +-51853,-53534,-55178,-56778,-58333,-59838,-61289,-62684, +-64019,-65290,-66494,-67629,-68692,-69679,-70590,-71420, +-72169,-72835,-73415,-73908,-74313,-74630,-74856,-74992, + 75038, +}; + +/*******************************************************/ +/* layer 2 tables */ + +static const int sblimit_table[5] = { 27 , 30 , 8, 12 , 30 }; + +static const int quant_steps[17] = { + 3, 5, 7, 9, 15, + 31, 63, 127, 255, 511, + 1023, 2047, 4095, 8191, 16383, + 32767, 65535 +}; + +/* we use a negative value if grouped */ +static const int quant_bits[17] = { + -5, -7, 3, -10, 4, + 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, + 15, 16 +}; + +/* encoding tables which give the quantization index. Note how it is + possible to store them efficiently ! */ +static const unsigned char alloc_table_0[] = { + 4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, +}; + +static const unsigned char alloc_table_1[] = { + 4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 4, 0, 2, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 3, 0, 1, 2, 3, 4, 5, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, + 2, 0, 1, 16, +}; + +static const unsigned char alloc_table_2[] = { + 4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, +}; + +static const unsigned char alloc_table_3[] = { + 4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 4, 0, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, +}; + +static const unsigned char alloc_table_4[] = { + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 4, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 3, 0, 1, 3, 4, 5, 6, 7, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, + 2, 0, 1, 3, +}; + +static const unsigned char *alloc_tables[5] = +{ alloc_table_0, alloc_table_1, alloc_table_2, alloc_table_3, alloc_table_4, }; + +/*******************************************************/ +/* layer 3 tables */ + +/* layer3 scale factor size */ +static const uint8_t slen_table[2][16] = { + { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 }, + { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 }, +}; + +/* number of lsf scale factors for a given size */ +static const uint8_t lsf_nsf_table[6][3][4] = { + { { 6, 5, 5, 5 }, { 9, 9, 9, 9 }, { 6, 9, 9, 9 } }, + { { 6, 5, 7, 3 }, { 9, 9, 12, 6 }, { 6, 9, 12, 6 } }, + { { 11, 10, 0, 0 }, { 18, 18, 0, 0 }, { 15, 18, 0, 0 } }, + { { 7, 7, 7, 0 }, { 12, 12, 12, 0 }, { 6, 15, 12, 0 } }, + { { 6, 6, 6, 3 }, { 12, 9, 9, 6 }, { 6, 12, 9, 6 } }, + { { 8, 8, 5, 0 }, { 15, 12, 9, 0 }, { 6, 18, 9, 0 } }, +}; + +/* mpegaudio layer 3 huffman tables */ + +static const uint16_t mpa_huffcodes_1[4] = { + 0x0001, 0x0001, 0x0001, 0x0000, +}; + +static const uint8_t mpa_huffbits_1[4] = { + 1, 3, 2, 3, +}; + +static const uint16_t mpa_huffcodes_2[9] = { + 0x0001, 0x0002, 0x0001, 0x0003, 0x0001, 0x0001, 0x0003, 0x0002, + 0x0000, +}; + +static const uint8_t mpa_huffbits_2[9] = { + 1, 3, 6, 3, 3, 5, 5, 5, + 6, +}; + +static const uint16_t mpa_huffcodes_3[9] = { + 0x0003, 0x0002, 0x0001, 0x0001, 0x0001, 0x0001, 0x0003, 0x0002, + 0x0000, +}; + +static const uint8_t mpa_huffbits_3[9] = { + 2, 2, 6, 3, 2, 5, 5, 5, + 6, +}; + +static const uint16_t mpa_huffcodes_5[16] = { + 0x0001, 0x0002, 0x0006, 0x0005, 0x0003, 0x0001, 0x0004, 0x0004, + 0x0007, 0x0005, 0x0007, 0x0001, 0x0006, 0x0001, 0x0001, 0x0000, +}; + +static const uint8_t mpa_huffbits_5[16] = { + 1, 3, 6, 7, 3, 3, 6, 7, + 6, 6, 7, 8, 7, 6, 7, 8, +}; + +static const uint16_t mpa_huffcodes_6[16] = { + 0x0007, 0x0003, 0x0005, 0x0001, 0x0006, 0x0002, 0x0003, 0x0002, + 0x0005, 0x0004, 0x0004, 0x0001, 0x0003, 0x0003, 0x0002, 0x0000, +}; + +static const uint8_t mpa_huffbits_6[16] = { + 3, 3, 5, 7, 3, 2, 4, 5, + 4, 4, 5, 6, 6, 5, 6, 7, +}; + +static const uint16_t mpa_huffcodes_7[36] = { + 0x0001, 0x0002, 0x000a, 0x0013, 0x0010, 0x000a, 0x0003, 0x0003, + 0x0007, 0x000a, 0x0005, 0x0003, 0x000b, 0x0004, 0x000d, 0x0011, + 0x0008, 0x0004, 0x000c, 0x000b, 0x0012, 0x000f, 0x000b, 0x0002, + 0x0007, 0x0006, 0x0009, 0x000e, 0x0003, 0x0001, 0x0006, 0x0004, + 0x0005, 0x0003, 0x0002, 0x0000, +}; + +static const uint8_t mpa_huffbits_7[36] = { + 1, 3, 6, 8, 8, 9, 3, 4, + 6, 7, 7, 8, 6, 5, 7, 8, + 8, 9, 7, 7, 8, 9, 9, 9, + 7, 7, 8, 9, 9, 10, 8, 8, + 9, 10, 10, 10, +}; + +static const uint16_t mpa_huffcodes_8[36] = { + 0x0003, 0x0004, 0x0006, 0x0012, 0x000c, 0x0005, 0x0005, 0x0001, + 0x0002, 0x0010, 0x0009, 0x0003, 0x0007, 0x0003, 0x0005, 0x000e, + 0x0007, 0x0003, 0x0013, 0x0011, 0x000f, 0x000d, 0x000a, 0x0004, + 0x000d, 0x0005, 0x0008, 0x000b, 0x0005, 0x0001, 0x000c, 0x0004, + 0x0004, 0x0001, 0x0001, 0x0000, +}; + +static const uint8_t mpa_huffbits_8[36] = { + 2, 3, 6, 8, 8, 9, 3, 2, + 4, 8, 8, 8, 6, 4, 6, 8, + 8, 9, 8, 8, 8, 9, 9, 10, + 8, 7, 8, 9, 10, 10, 9, 8, + 9, 9, 11, 11, +}; + +static const uint16_t mpa_huffcodes_9[36] = { + 0x0007, 0x0005, 0x0009, 0x000e, 0x000f, 0x0007, 0x0006, 0x0004, + 0x0005, 0x0005, 0x0006, 0x0007, 0x0007, 0x0006, 0x0008, 0x0008, + 0x0008, 0x0005, 0x000f, 0x0006, 0x0009, 0x000a, 0x0005, 0x0001, + 0x000b, 0x0007, 0x0009, 0x0006, 0x0004, 0x0001, 0x000e, 0x0004, + 0x0006, 0x0002, 0x0006, 0x0000, +}; + +static const uint8_t mpa_huffbits_9[36] = { + 3, 3, 5, 6, 8, 9, 3, 3, + 4, 5, 6, 8, 4, 4, 5, 6, + 7, 8, 6, 5, 6, 7, 7, 8, + 7, 6, 7, 7, 8, 9, 8, 7, + 8, 8, 9, 9, +}; + +static const uint16_t mpa_huffcodes_10[64] = { + 0x0001, 0x0002, 0x000a, 0x0017, 0x0023, 0x001e, 0x000c, 0x0011, + 0x0003, 0x0003, 0x0008, 0x000c, 0x0012, 0x0015, 0x000c, 0x0007, + 0x000b, 0x0009, 0x000f, 0x0015, 0x0020, 0x0028, 0x0013, 0x0006, + 0x000e, 0x000d, 0x0016, 0x0022, 0x002e, 0x0017, 0x0012, 0x0007, + 0x0014, 0x0013, 0x0021, 0x002f, 0x001b, 0x0016, 0x0009, 0x0003, + 0x001f, 0x0016, 0x0029, 0x001a, 0x0015, 0x0014, 0x0005, 0x0003, + 0x000e, 0x000d, 0x000a, 0x000b, 0x0010, 0x0006, 0x0005, 0x0001, + 0x0009, 0x0008, 0x0007, 0x0008, 0x0004, 0x0004, 0x0002, 0x0000, +}; + +static const uint8_t mpa_huffbits_10[64] = { + 1, 3, 6, 8, 9, 9, 9, 10, + 3, 4, 6, 7, 8, 9, 8, 8, + 6, 6, 7, 8, 9, 10, 9, 9, + 7, 7, 8, 9, 10, 10, 9, 10, + 8, 8, 9, 10, 10, 10, 10, 10, + 9, 9, 10, 10, 11, 11, 10, 11, + 8, 8, 9, 10, 10, 10, 11, 11, + 9, 8, 9, 10, 10, 11, 11, 11, +}; + +static const uint16_t mpa_huffcodes_11[64] = { + 0x0003, 0x0004, 0x000a, 0x0018, 0x0022, 0x0021, 0x0015, 0x000f, + 0x0005, 0x0003, 0x0004, 0x000a, 0x0020, 0x0011, 0x000b, 0x000a, + 0x000b, 0x0007, 0x000d, 0x0012, 0x001e, 0x001f, 0x0014, 0x0005, + 0x0019, 0x000b, 0x0013, 0x003b, 0x001b, 0x0012, 0x000c, 0x0005, + 0x0023, 0x0021, 0x001f, 0x003a, 0x001e, 0x0010, 0x0007, 0x0005, + 0x001c, 0x001a, 0x0020, 0x0013, 0x0011, 0x000f, 0x0008, 0x000e, + 0x000e, 0x000c, 0x0009, 0x000d, 0x000e, 0x0009, 0x0004, 0x0001, + 0x000b, 0x0004, 0x0006, 0x0006, 0x0006, 0x0003, 0x0002, 0x0000, +}; + +static const uint8_t mpa_huffbits_11[64] = { + 2, 3, 5, 7, 8, 9, 8, 9, + 3, 3, 4, 6, 8, 8, 7, 8, + 5, 5, 6, 7, 8, 9, 8, 8, + 7, 6, 7, 9, 8, 10, 8, 9, + 8, 8, 8, 9, 9, 10, 9, 10, + 8, 8, 9, 10, 10, 11, 10, 11, + 8, 7, 7, 8, 9, 10, 10, 10, + 8, 7, 8, 9, 10, 10, 10, 10, +}; + +static const uint16_t mpa_huffcodes_12[64] = { + 0x0009, 0x0006, 0x0010, 0x0021, 0x0029, 0x0027, 0x0026, 0x001a, + 0x0007, 0x0005, 0x0006, 0x0009, 0x0017, 0x0010, 0x001a, 0x000b, + 0x0011, 0x0007, 0x000b, 0x000e, 0x0015, 0x001e, 0x000a, 0x0007, + 0x0011, 0x000a, 0x000f, 0x000c, 0x0012, 0x001c, 0x000e, 0x0005, + 0x0020, 0x000d, 0x0016, 0x0013, 0x0012, 0x0010, 0x0009, 0x0005, + 0x0028, 0x0011, 0x001f, 0x001d, 0x0011, 0x000d, 0x0004, 0x0002, + 0x001b, 0x000c, 0x000b, 0x000f, 0x000a, 0x0007, 0x0004, 0x0001, + 0x001b, 0x000c, 0x0008, 0x000c, 0x0006, 0x0003, 0x0001, 0x0000, +}; + +static const uint8_t mpa_huffbits_12[64] = { + 4, 3, 5, 7, 8, 9, 9, 9, + 3, 3, 4, 5, 7, 7, 8, 8, + 5, 4, 5, 6, 7, 8, 7, 8, + 6, 5, 6, 6, 7, 8, 8, 8, + 7, 6, 7, 7, 8, 8, 8, 9, + 8, 7, 8, 8, 8, 9, 8, 9, + 8, 7, 7, 8, 8, 9, 9, 10, + 9, 8, 8, 9, 9, 9, 9, 10, +}; + +static const uint16_t mpa_huffcodes_13[256] = { + 0x0001, 0x0005, 0x000e, 0x0015, 0x0022, 0x0033, 0x002e, 0x0047, + 0x002a, 0x0034, 0x0044, 0x0034, 0x0043, 0x002c, 0x002b, 0x0013, + 0x0003, 0x0004, 0x000c, 0x0013, 0x001f, 0x001a, 0x002c, 0x0021, + 0x001f, 0x0018, 0x0020, 0x0018, 0x001f, 0x0023, 0x0016, 0x000e, + 0x000f, 0x000d, 0x0017, 0x0024, 0x003b, 0x0031, 0x004d, 0x0041, + 0x001d, 0x0028, 0x001e, 0x0028, 0x001b, 0x0021, 0x002a, 0x0010, + 0x0016, 0x0014, 0x0025, 0x003d, 0x0038, 0x004f, 0x0049, 0x0040, + 0x002b, 0x004c, 0x0038, 0x0025, 0x001a, 0x001f, 0x0019, 0x000e, + 0x0023, 0x0010, 0x003c, 0x0039, 0x0061, 0x004b, 0x0072, 0x005b, + 0x0036, 0x0049, 0x0037, 0x0029, 0x0030, 0x0035, 0x0017, 0x0018, + 0x003a, 0x001b, 0x0032, 0x0060, 0x004c, 0x0046, 0x005d, 0x0054, + 0x004d, 0x003a, 0x004f, 0x001d, 0x004a, 0x0031, 0x0029, 0x0011, + 0x002f, 0x002d, 0x004e, 0x004a, 0x0073, 0x005e, 0x005a, 0x004f, + 0x0045, 0x0053, 0x0047, 0x0032, 0x003b, 0x0026, 0x0024, 0x000f, + 0x0048, 0x0022, 0x0038, 0x005f, 0x005c, 0x0055, 0x005b, 0x005a, + 0x0056, 0x0049, 0x004d, 0x0041, 0x0033, 0x002c, 0x002b, 0x002a, + 0x002b, 0x0014, 0x001e, 0x002c, 0x0037, 0x004e, 0x0048, 0x0057, + 0x004e, 0x003d, 0x002e, 0x0036, 0x0025, 0x001e, 0x0014, 0x0010, + 0x0035, 0x0019, 0x0029, 0x0025, 0x002c, 0x003b, 0x0036, 0x0051, + 0x0042, 0x004c, 0x0039, 0x0036, 0x0025, 0x0012, 0x0027, 0x000b, + 0x0023, 0x0021, 0x001f, 0x0039, 0x002a, 0x0052, 0x0048, 0x0050, + 0x002f, 0x003a, 0x0037, 0x0015, 0x0016, 0x001a, 0x0026, 0x0016, + 0x0035, 0x0019, 0x0017, 0x0026, 0x0046, 0x003c, 0x0033, 0x0024, + 0x0037, 0x001a, 0x0022, 0x0017, 0x001b, 0x000e, 0x0009, 0x0007, + 0x0022, 0x0020, 0x001c, 0x0027, 0x0031, 0x004b, 0x001e, 0x0034, + 0x0030, 0x0028, 0x0034, 0x001c, 0x0012, 0x0011, 0x0009, 0x0005, + 0x002d, 0x0015, 0x0022, 0x0040, 0x0038, 0x0032, 0x0031, 0x002d, + 0x001f, 0x0013, 0x000c, 0x000f, 0x000a, 0x0007, 0x0006, 0x0003, + 0x0030, 0x0017, 0x0014, 0x0027, 0x0024, 0x0023, 0x0035, 0x0015, + 0x0010, 0x0017, 0x000d, 0x000a, 0x0006, 0x0001, 0x0004, 0x0002, + 0x0010, 0x000f, 0x0011, 0x001b, 0x0019, 0x0014, 0x001d, 0x000b, + 0x0011, 0x000c, 0x0010, 0x0008, 0x0001, 0x0001, 0x0000, 0x0001, +}; + +static const uint8_t mpa_huffbits_13[256] = { + 1, 4, 6, 7, 8, 9, 9, 10, + 9, 10, 11, 11, 12, 12, 13, 13, + 3, 4, 6, 7, 8, 8, 9, 9, + 9, 9, 10, 10, 11, 12, 12, 12, + 6, 6, 7, 8, 9, 9, 10, 10, + 9, 10, 10, 11, 11, 12, 13, 13, + 7, 7, 8, 9, 9, 10, 10, 10, + 10, 11, 11, 11, 11, 12, 13, 13, + 8, 7, 9, 9, 10, 10, 11, 11, + 10, 11, 11, 12, 12, 13, 13, 14, + 9, 8, 9, 10, 10, 10, 11, 11, + 11, 11, 12, 11, 13, 13, 14, 14, + 9, 9, 10, 10, 11, 11, 11, 11, + 11, 12, 12, 12, 13, 13, 14, 14, + 10, 9, 10, 11, 11, 11, 12, 12, + 12, 12, 13, 13, 13, 14, 16, 16, + 9, 8, 9, 10, 10, 11, 11, 12, + 12, 12, 12, 13, 13, 14, 15, 15, + 10, 9, 10, 10, 11, 11, 11, 13, + 12, 13, 13, 14, 14, 14, 16, 15, + 10, 10, 10, 11, 11, 12, 12, 13, + 12, 13, 14, 13, 14, 15, 16, 17, + 11, 10, 10, 11, 12, 12, 12, 12, + 13, 13, 13, 14, 15, 15, 15, 16, + 11, 11, 11, 12, 12, 13, 12, 13, + 14, 14, 15, 15, 15, 16, 16, 16, + 12, 11, 12, 13, 13, 13, 14, 14, + 14, 14, 14, 15, 16, 15, 16, 16, + 13, 12, 12, 13, 13, 13, 15, 14, + 14, 17, 15, 15, 15, 17, 16, 16, + 12, 12, 13, 14, 14, 14, 15, 14, + 15, 15, 16, 16, 19, 18, 19, 16, +}; + +static const uint16_t mpa_huffcodes_15[256] = { + 0x0007, 0x000c, 0x0012, 0x0035, 0x002f, 0x004c, 0x007c, 0x006c, + 0x0059, 0x007b, 0x006c, 0x0077, 0x006b, 0x0051, 0x007a, 0x003f, + 0x000d, 0x0005, 0x0010, 0x001b, 0x002e, 0x0024, 0x003d, 0x0033, + 0x002a, 0x0046, 0x0034, 0x0053, 0x0041, 0x0029, 0x003b, 0x0024, + 0x0013, 0x0011, 0x000f, 0x0018, 0x0029, 0x0022, 0x003b, 0x0030, + 0x0028, 0x0040, 0x0032, 0x004e, 0x003e, 0x0050, 0x0038, 0x0021, + 0x001d, 0x001c, 0x0019, 0x002b, 0x0027, 0x003f, 0x0037, 0x005d, + 0x004c, 0x003b, 0x005d, 0x0048, 0x0036, 0x004b, 0x0032, 0x001d, + 0x0034, 0x0016, 0x002a, 0x0028, 0x0043, 0x0039, 0x005f, 0x004f, + 0x0048, 0x0039, 0x0059, 0x0045, 0x0031, 0x0042, 0x002e, 0x001b, + 0x004d, 0x0025, 0x0023, 0x0042, 0x003a, 0x0034, 0x005b, 0x004a, + 0x003e, 0x0030, 0x004f, 0x003f, 0x005a, 0x003e, 0x0028, 0x0026, + 0x007d, 0x0020, 0x003c, 0x0038, 0x0032, 0x005c, 0x004e, 0x0041, + 0x0037, 0x0057, 0x0047, 0x0033, 0x0049, 0x0033, 0x0046, 0x001e, + 0x006d, 0x0035, 0x0031, 0x005e, 0x0058, 0x004b, 0x0042, 0x007a, + 0x005b, 0x0049, 0x0038, 0x002a, 0x0040, 0x002c, 0x0015, 0x0019, + 0x005a, 0x002b, 0x0029, 0x004d, 0x0049, 0x003f, 0x0038, 0x005c, + 0x004d, 0x0042, 0x002f, 0x0043, 0x0030, 0x0035, 0x0024, 0x0014, + 0x0047, 0x0022, 0x0043, 0x003c, 0x003a, 0x0031, 0x0058, 0x004c, + 0x0043, 0x006a, 0x0047, 0x0036, 0x0026, 0x0027, 0x0017, 0x000f, + 0x006d, 0x0035, 0x0033, 0x002f, 0x005a, 0x0052, 0x003a, 0x0039, + 0x0030, 0x0048, 0x0039, 0x0029, 0x0017, 0x001b, 0x003e, 0x0009, + 0x0056, 0x002a, 0x0028, 0x0025, 0x0046, 0x0040, 0x0034, 0x002b, + 0x0046, 0x0037, 0x002a, 0x0019, 0x001d, 0x0012, 0x000b, 0x000b, + 0x0076, 0x0044, 0x001e, 0x0037, 0x0032, 0x002e, 0x004a, 0x0041, + 0x0031, 0x0027, 0x0018, 0x0010, 0x0016, 0x000d, 0x000e, 0x0007, + 0x005b, 0x002c, 0x0027, 0x0026, 0x0022, 0x003f, 0x0034, 0x002d, + 0x001f, 0x0034, 0x001c, 0x0013, 0x000e, 0x0008, 0x0009, 0x0003, + 0x007b, 0x003c, 0x003a, 0x0035, 0x002f, 0x002b, 0x0020, 0x0016, + 0x0025, 0x0018, 0x0011, 0x000c, 0x000f, 0x000a, 0x0002, 0x0001, + 0x0047, 0x0025, 0x0022, 0x001e, 0x001c, 0x0014, 0x0011, 0x001a, + 0x0015, 0x0010, 0x000a, 0x0006, 0x0008, 0x0006, 0x0002, 0x0000, +}; + +static const uint8_t mpa_huffbits_15[256] = { + 3, 4, 5, 7, 7, 8, 9, 9, + 9, 10, 10, 11, 11, 11, 12, 13, + 4, 3, 5, 6, 7, 7, 8, 8, + 8, 9, 9, 10, 10, 10, 11, 11, + 5, 5, 5, 6, 7, 7, 8, 8, + 8, 9, 9, 10, 10, 11, 11, 11, + 6, 6, 6, 7, 7, 8, 8, 9, + 9, 9, 10, 10, 10, 11, 11, 11, + 7, 6, 7, 7, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 11, 11, 11, + 8, 7, 7, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 11, 11, 11, 12, + 9, 7, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 11, 11, 12, 12, + 9, 8, 8, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 11, 11, 11, 12, + 9, 8, 8, 9, 9, 9, 9, 10, + 10, 10, 10, 11, 11, 12, 12, 12, + 9, 8, 9, 9, 9, 9, 10, 10, + 10, 11, 11, 11, 11, 12, 12, 12, + 10, 9, 9, 9, 10, 10, 10, 10, + 10, 11, 11, 11, 11, 12, 13, 12, + 10, 9, 9, 9, 10, 10, 10, 10, + 11, 11, 11, 11, 12, 12, 12, 13, + 11, 10, 9, 10, 10, 10, 11, 11, + 11, 11, 11, 11, 12, 12, 13, 13, + 11, 10, 10, 10, 10, 11, 11, 11, + 11, 12, 12, 12, 12, 12, 13, 13, + 12, 11, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 12, 13, + 12, 11, 11, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 13, 13, 13, 13, +}; + +static const uint16_t mpa_huffcodes_16[256] = { + 0x0001, 0x0005, 0x000e, 0x002c, 0x004a, 0x003f, 0x006e, 0x005d, + 0x00ac, 0x0095, 0x008a, 0x00f2, 0x00e1, 0x00c3, 0x0178, 0x0011, + 0x0003, 0x0004, 0x000c, 0x0014, 0x0023, 0x003e, 0x0035, 0x002f, + 0x0053, 0x004b, 0x0044, 0x0077, 0x00c9, 0x006b, 0x00cf, 0x0009, + 0x000f, 0x000d, 0x0017, 0x0026, 0x0043, 0x003a, 0x0067, 0x005a, + 0x00a1, 0x0048, 0x007f, 0x0075, 0x006e, 0x00d1, 0x00ce, 0x0010, + 0x002d, 0x0015, 0x0027, 0x0045, 0x0040, 0x0072, 0x0063, 0x0057, + 0x009e, 0x008c, 0x00fc, 0x00d4, 0x00c7, 0x0183, 0x016d, 0x001a, + 0x004b, 0x0024, 0x0044, 0x0041, 0x0073, 0x0065, 0x00b3, 0x00a4, + 0x009b, 0x0108, 0x00f6, 0x00e2, 0x018b, 0x017e, 0x016a, 0x0009, + 0x0042, 0x001e, 0x003b, 0x0038, 0x0066, 0x00b9, 0x00ad, 0x0109, + 0x008e, 0x00fd, 0x00e8, 0x0190, 0x0184, 0x017a, 0x01bd, 0x0010, + 0x006f, 0x0036, 0x0034, 0x0064, 0x00b8, 0x00b2, 0x00a0, 0x0085, + 0x0101, 0x00f4, 0x00e4, 0x00d9, 0x0181, 0x016e, 0x02cb, 0x000a, + 0x0062, 0x0030, 0x005b, 0x0058, 0x00a5, 0x009d, 0x0094, 0x0105, + 0x00f8, 0x0197, 0x018d, 0x0174, 0x017c, 0x0379, 0x0374, 0x0008, + 0x0055, 0x0054, 0x0051, 0x009f, 0x009c, 0x008f, 0x0104, 0x00f9, + 0x01ab, 0x0191, 0x0188, 0x017f, 0x02d7, 0x02c9, 0x02c4, 0x0007, + 0x009a, 0x004c, 0x0049, 0x008d, 0x0083, 0x0100, 0x00f5, 0x01aa, + 0x0196, 0x018a, 0x0180, 0x02df, 0x0167, 0x02c6, 0x0160, 0x000b, + 0x008b, 0x0081, 0x0043, 0x007d, 0x00f7, 0x00e9, 0x00e5, 0x00db, + 0x0189, 0x02e7, 0x02e1, 0x02d0, 0x0375, 0x0372, 0x01b7, 0x0004, + 0x00f3, 0x0078, 0x0076, 0x0073, 0x00e3, 0x00df, 0x018c, 0x02ea, + 0x02e6, 0x02e0, 0x02d1, 0x02c8, 0x02c2, 0x00df, 0x01b4, 0x0006, + 0x00ca, 0x00e0, 0x00de, 0x00da, 0x00d8, 0x0185, 0x0182, 0x017d, + 0x016c, 0x0378, 0x01bb, 0x02c3, 0x01b8, 0x01b5, 0x06c0, 0x0004, + 0x02eb, 0x00d3, 0x00d2, 0x00d0, 0x0172, 0x017b, 0x02de, 0x02d3, + 0x02ca, 0x06c7, 0x0373, 0x036d, 0x036c, 0x0d83, 0x0361, 0x0002, + 0x0179, 0x0171, 0x0066, 0x00bb, 0x02d6, 0x02d2, 0x0166, 0x02c7, + 0x02c5, 0x0362, 0x06c6, 0x0367, 0x0d82, 0x0366, 0x01b2, 0x0000, + 0x000c, 0x000a, 0x0007, 0x000b, 0x000a, 0x0011, 0x000b, 0x0009, + 0x000d, 0x000c, 0x000a, 0x0007, 0x0005, 0x0003, 0x0001, 0x0003, +}; + +static const uint8_t mpa_huffbits_16[256] = { + 1, 4, 6, 8, 9, 9, 10, 10, + 11, 11, 11, 12, 12, 12, 13, 9, + 3, 4, 6, 7, 8, 9, 9, 9, + 10, 10, 10, 11, 12, 11, 12, 8, + 6, 6, 7, 8, 9, 9, 10, 10, + 11, 10, 11, 11, 11, 12, 12, 9, + 8, 7, 8, 9, 9, 10, 10, 10, + 11, 11, 12, 12, 12, 13, 13, 10, + 9, 8, 9, 9, 10, 10, 11, 11, + 11, 12, 12, 12, 13, 13, 13, 9, + 9, 8, 9, 9, 10, 11, 11, 12, + 11, 12, 12, 13, 13, 13, 14, 10, + 10, 9, 9, 10, 11, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 14, 10, + 10, 9, 10, 10, 11, 11, 11, 12, + 12, 13, 13, 13, 13, 15, 15, 10, + 10, 10, 10, 11, 11, 11, 12, 12, + 13, 13, 13, 13, 14, 14, 14, 10, + 11, 10, 10, 11, 11, 12, 12, 13, + 13, 13, 13, 14, 13, 14, 13, 11, + 11, 11, 10, 11, 12, 12, 12, 12, + 13, 14, 14, 14, 15, 15, 14, 10, + 12, 11, 11, 11, 12, 12, 13, 14, + 14, 14, 14, 14, 14, 13, 14, 11, + 12, 12, 12, 12, 12, 13, 13, 13, + 13, 15, 14, 14, 14, 14, 16, 11, + 14, 12, 12, 12, 13, 13, 14, 14, + 14, 16, 15, 15, 15, 17, 15, 11, + 13, 13, 11, 12, 14, 14, 13, 14, + 14, 15, 16, 15, 17, 15, 14, 11, + 9, 8, 8, 9, 9, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 8, +}; + +static const uint16_t mpa_huffcodes_24[256] = { + 0x000f, 0x000d, 0x002e, 0x0050, 0x0092, 0x0106, 0x00f8, 0x01b2, + 0x01aa, 0x029d, 0x028d, 0x0289, 0x026d, 0x0205, 0x0408, 0x0058, + 0x000e, 0x000c, 0x0015, 0x0026, 0x0047, 0x0082, 0x007a, 0x00d8, + 0x00d1, 0x00c6, 0x0147, 0x0159, 0x013f, 0x0129, 0x0117, 0x002a, + 0x002f, 0x0016, 0x0029, 0x004a, 0x0044, 0x0080, 0x0078, 0x00dd, + 0x00cf, 0x00c2, 0x00b6, 0x0154, 0x013b, 0x0127, 0x021d, 0x0012, + 0x0051, 0x0027, 0x004b, 0x0046, 0x0086, 0x007d, 0x0074, 0x00dc, + 0x00cc, 0x00be, 0x00b2, 0x0145, 0x0137, 0x0125, 0x010f, 0x0010, + 0x0093, 0x0048, 0x0045, 0x0087, 0x007f, 0x0076, 0x0070, 0x00d2, + 0x00c8, 0x00bc, 0x0160, 0x0143, 0x0132, 0x011d, 0x021c, 0x000e, + 0x0107, 0x0042, 0x0081, 0x007e, 0x0077, 0x0072, 0x00d6, 0x00ca, + 0x00c0, 0x00b4, 0x0155, 0x013d, 0x012d, 0x0119, 0x0106, 0x000c, + 0x00f9, 0x007b, 0x0079, 0x0075, 0x0071, 0x00d7, 0x00ce, 0x00c3, + 0x00b9, 0x015b, 0x014a, 0x0134, 0x0123, 0x0110, 0x0208, 0x000a, + 0x01b3, 0x0073, 0x006f, 0x006d, 0x00d3, 0x00cb, 0x00c4, 0x00bb, + 0x0161, 0x014c, 0x0139, 0x012a, 0x011b, 0x0213, 0x017d, 0x0011, + 0x01ab, 0x00d4, 0x00d0, 0x00cd, 0x00c9, 0x00c1, 0x00ba, 0x00b1, + 0x00a9, 0x0140, 0x012f, 0x011e, 0x010c, 0x0202, 0x0179, 0x0010, + 0x014f, 0x00c7, 0x00c5, 0x00bf, 0x00bd, 0x00b5, 0x00ae, 0x014d, + 0x0141, 0x0131, 0x0121, 0x0113, 0x0209, 0x017b, 0x0173, 0x000b, + 0x029c, 0x00b8, 0x00b7, 0x00b3, 0x00af, 0x0158, 0x014b, 0x013a, + 0x0130, 0x0122, 0x0115, 0x0212, 0x017f, 0x0175, 0x016e, 0x000a, + 0x028c, 0x015a, 0x00ab, 0x00a8, 0x00a4, 0x013e, 0x0135, 0x012b, + 0x011f, 0x0114, 0x0107, 0x0201, 0x0177, 0x0170, 0x016a, 0x0006, + 0x0288, 0x0142, 0x013c, 0x0138, 0x0133, 0x012e, 0x0124, 0x011c, + 0x010d, 0x0105, 0x0200, 0x0178, 0x0172, 0x016c, 0x0167, 0x0004, + 0x026c, 0x012c, 0x0128, 0x0126, 0x0120, 0x011a, 0x0111, 0x010a, + 0x0203, 0x017c, 0x0176, 0x0171, 0x016d, 0x0169, 0x0165, 0x0002, + 0x0409, 0x0118, 0x0116, 0x0112, 0x010b, 0x0108, 0x0103, 0x017e, + 0x017a, 0x0174, 0x016f, 0x016b, 0x0168, 0x0166, 0x0164, 0x0000, + 0x002b, 0x0014, 0x0013, 0x0011, 0x000f, 0x000d, 0x000b, 0x0009, + 0x0007, 0x0006, 0x0004, 0x0007, 0x0005, 0x0003, 0x0001, 0x0003, +}; + +static const uint8_t mpa_huffbits_24[256] = { + 4, 4, 6, 7, 8, 9, 9, 10, + 10, 11, 11, 11, 11, 11, 12, 9, + 4, 4, 5, 6, 7, 8, 8, 9, + 9, 9, 10, 10, 10, 10, 10, 8, + 6, 5, 6, 7, 7, 8, 8, 9, + 9, 9, 9, 10, 10, 10, 11, 7, + 7, 6, 7, 7, 8, 8, 8, 9, + 9, 9, 9, 10, 10, 10, 10, 7, + 8, 7, 7, 8, 8, 8, 8, 9, + 9, 9, 10, 10, 10, 10, 11, 7, + 9, 7, 8, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 10, 10, 7, + 9, 8, 8, 8, 8, 9, 9, 9, + 9, 10, 10, 10, 10, 10, 11, 7, + 10, 8, 8, 8, 9, 9, 9, 9, + 10, 10, 10, 10, 10, 11, 11, 8, + 10, 9, 9, 9, 9, 9, 9, 9, + 9, 10, 10, 10, 10, 11, 11, 8, + 10, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 11, 11, 11, 8, + 11, 9, 9, 9, 9, 10, 10, 10, + 10, 10, 10, 11, 11, 11, 11, 8, + 11, 10, 9, 9, 9, 10, 10, 10, + 10, 10, 10, 11, 11, 11, 11, 8, + 11, 10, 10, 10, 10, 10, 10, 10, + 10, 10, 11, 11, 11, 11, 11, 8, + 11, 10, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 11, 11, 11, 8, + 12, 10, 10, 10, 10, 10, 10, 11, + 11, 11, 11, 11, 11, 11, 11, 8, + 8, 7, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 8, 8, 8, 8, 4, +}; + +static const HuffTable mpa_huff_tables[16] = { +{ 1, NULL, NULL }, +{ 2, mpa_huffbits_1, mpa_huffcodes_1 }, +{ 3, mpa_huffbits_2, mpa_huffcodes_2 }, +{ 3, mpa_huffbits_3, mpa_huffcodes_3 }, +{ 4, mpa_huffbits_5, mpa_huffcodes_5 }, +{ 4, mpa_huffbits_6, mpa_huffcodes_6 }, +{ 6, mpa_huffbits_7, mpa_huffcodes_7 }, +{ 6, mpa_huffbits_8, mpa_huffcodes_8 }, +{ 6, mpa_huffbits_9, mpa_huffcodes_9 }, +{ 8, mpa_huffbits_10, mpa_huffcodes_10 }, +{ 8, mpa_huffbits_11, mpa_huffcodes_11 }, +{ 8, mpa_huffbits_12, mpa_huffcodes_12 }, +{ 16, mpa_huffbits_13, mpa_huffcodes_13 }, +{ 16, mpa_huffbits_15, mpa_huffcodes_15 }, +{ 16, mpa_huffbits_16, mpa_huffcodes_16 }, +{ 16, mpa_huffbits_24, mpa_huffcodes_24 }, +}; + +static const uint8_t mpa_huff_data[32][2] = { +{ 0, 0 }, +{ 1, 0 }, +{ 2, 0 }, +{ 3, 0 }, +{ 0, 0 }, +{ 4, 0 }, +{ 5, 0 }, +{ 6, 0 }, +{ 7, 0 }, +{ 8, 0 }, +{ 9, 0 }, +{ 10, 0 }, +{ 11, 0 }, +{ 12, 0 }, +{ 0, 0 }, +{ 13, 0 }, +{ 14, 1 }, +{ 14, 2 }, +{ 14, 3 }, +{ 14, 4 }, +{ 14, 6 }, +{ 14, 8 }, +{ 14, 10 }, +{ 14, 13 }, +{ 15, 4 }, +{ 15, 5 }, +{ 15, 6 }, +{ 15, 7 }, +{ 15, 8 }, +{ 15, 9 }, +{ 15, 11 }, +{ 15, 13 }, +}; + + +/* huffman tables for quadrules */ +static uint8_t mpa_quad_codes[2][16] = { + { 1, 5, 4, 5, 6, 5, 4, 4, 7, 3, 6, 0, 7, 2, 3, 1, }, + { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, }, +}; + +static uint8_t mpa_quad_bits[2][16] = { + { 1, 4, 4, 5, 4, 6, 5, 6, 4, 5, 5, 6, 5, 6, 6, 6, }, + { 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, }, +}; + +/* band size tables */ +static const uint8_t band_size_long[9][22] = { +{ 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, + 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158, }, /* 44100 */ +{ 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, + 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192, }, /* 48000 */ +{ 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, + 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26, }, /* 32000 */ +{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, }, /* 22050 */ +{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 18, 22, 26, 32, 38, 46, 52, 64, 70, 76, 36, }, /* 24000 */ +{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, }, /* 16000 */ +{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, }, /* 11025 */ +{ 6, 6, 6, 6, 6, 6, 8, 10, 12, 14, 16, + 20, 24, 28, 32, 38, 46, 52, 60, 68, 58, 54, }, /* 12000 */ +{ 12, 12, 12, 12, 12, 12, 16, 20, 24, 28, 32, + 40, 48, 56, 64, 76, 90, 2, 2, 2, 2, 2, }, /* 8000 */ +}; + +static const uint8_t band_size_short[9][13] = { +{ 4, 4, 4, 4, 6, 8, 10, 12, 14, 18, 22, 30, 56, }, /* 44100 */ +{ 4, 4, 4, 4, 6, 6, 10, 12, 14, 16, 20, 26, 66, }, /* 48000 */ +{ 4, 4, 4, 4, 6, 8, 12, 16, 20, 26, 34, 42, 12, }, /* 32000 */ +{ 4, 4, 4, 6, 6, 8, 10, 14, 18, 26, 32, 42, 18, }, /* 22050 */ +{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 32, 44, 12, }, /* 24000 */ +{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 16000 */ +{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 11025 */ +{ 4, 4, 4, 6, 8, 10, 12, 14, 18, 24, 30, 40, 18, }, /* 12000 */ +{ 8, 8, 8, 12, 16, 20, 24, 28, 36, 2, 2, 2, 26, }, /* 8000 */ +}; + +static const uint8_t mpa_pretab[2][22] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 }, +}; + +/* table for alias reduction (XXX: store it as integer !) */ +static const float ci_table[8] = { + -0.6f, -0.535f, -0.33f, -0.185f, -0.095f, -0.041f, -0.0142f, -0.0037f, +}; diff --git a/src/Client/GUI/decoder/mpegaudio.h b/src/Client/GUI/decoder/mpegaudio.h new file mode 100644 index 0000000..51f0291 --- /dev/null +++ b/src/Client/GUI/decoder/mpegaudio.h @@ -0,0 +1,17 @@ +/* Modified slightly by Matt Campbell for the + stand-alone mpaudec library. Based on mpegaudio.h from libavcodec. */ + +/* max frame size, in samples */ +#define MPA_FRAME_SIZE 1152 + +/* max compressed frame size */ +#define MPA_MAX_CODED_FRAME_SIZE 1792 + +#define MPA_MAX_CHANNELS 2 + +#define SBLIMIT 32 /* number of subbands */ + +#define MPA_STEREO 0 +#define MPA_JSTEREO 1 +#define MPA_DUAL 2 +#define MPA_MONO 3 diff --git a/src/Client/GUI/ikpMP3.cpp b/src/Client/GUI/ikpMP3.cpp new file mode 100644 index 0000000..fc20eb5 --- /dev/null +++ b/src/Client/GUI/ikpMP3.cpp @@ -0,0 +1,41 @@ + +#include "irrklang/irrKlang.h" +#include +#include +#include "CIrrKlangAudioStreamLoaderMP3.h" + +using namespace irrklang; + +// this is the only function needed to be implemented for the plugin, it gets +// called by irrKlang when loaded. +// In this plugin, we create an audiostream loader class and register +// it at the engine, but a plugin can do anything. +// Be sure to name the function 'irrKlangPluginInit' and let the dll start with 'ikp'. + +#ifdef WIN32 +// Windows version +__declspec(dllexport) void __stdcall irrKlangPluginInit(ISoundEngine* engine, const char* version) +#else +// Linux version +void irrKlangPluginInit(ISoundEngine* engine, const char* version) +#endif +{ + // do some version security check to be sure that this plugin isn't begin used + // by some newer irrKlang version with changed interfaces which could possibily + // cause crashes. + + if (strcmp(version, IRR_KLANG_VERSION)) + { + printf("This MP3 plugin only supports irrKlang version %s, mp3 playback disabled.\n", IRR_KLANG_VERSION); + return; + } + + // create and register the loader + + CIrrKlangAudioStreamLoaderMP3* loader = new CIrrKlangAudioStreamLoaderMP3(); + engine->registerAudioStreamLoader(loader); + loader->drop(); + + // that's it, that's all. +} + diff --git a/src/Client/GUI/irrKlangSceneNode.cpp b/src/Client/GUI/irrKlangSceneNode.cpp new file mode 100644 index 0000000..4b288f4 --- /dev/null +++ b/src/Client/GUI/irrKlangSceneNode.cpp @@ -0,0 +1,551 @@ +#include "irrKlangSceneNode.h" + +// id for our scene node, 'ikng', short for 'irrklang'. +// If this line doesn't work, you are probably using irrlicht 1.3 or earlier. +// Then remove the MAKE_IRR_ID thing and replace it with a random number. +const int IRRKLANG_SCENE_NODE_ID = MAKE_IRR_ID('i','k','n','g'); + +// type name for our scene node +const char* irrKlangSceneNodeTypeName = "irrKlangSceneNode"; + + + +CIrrKlangSceneNode::CIrrKlangSceneNode(irrklang::ISoundEngine* soundEngine, + scene::ISceneNode* parent, + scene::ISceneManager* mgr, s32 id) + : scene::ISceneNode(parent, mgr, id), SoundEngine(soundEngine) +{ + setAutomaticCulling(scene::EAC_OFF); + + MinDistance = 20.0f; // a usual good value for irrlicht engine applications + MaxDistance = -1.0f; + PlayMode = EPM_RANDOM; + TimeMsDelayFinished = 0; + DeleteWhenFinished = false; + MaxTimeMsInterval = 5000; + MinTimeMsInterval = 1000; + Sound = 0; + PlayedCount = 0; + + if (SoundEngine) + SoundEngine->grab(); +} + + +CIrrKlangSceneNode::~CIrrKlangSceneNode() +{ + stop(); + + if (SoundEngine) + SoundEngine->drop(); +} + + +void CIrrKlangSceneNode::OnRegisterSceneNode() +{ + if (IsVisible && DebugDataVisible!=0) + SceneManager->registerNodeForRendering(this, irr::scene::ESNRP_TRANSPARENT); + + ISceneNode::OnRegisterSceneNode(); +} + + +void CIrrKlangSceneNode::OnAnimate(u32 timeMs) +{ + ISceneNode::OnAnimate(timeMs); + + // play the sound + + core::vector3df pos = getAbsolutePosition(); + + if (Sound) + Sound->setPosition(pos); + + switch(PlayMode) + { + case EPM_NOTHING: + return; + case EPM_RANDOM: + { + if (Sound && Sound->isFinished()) + { + Sound->drop(); + Sound = 0; + + // calculate next play time + + s32 delta = MaxTimeMsInterval - MinTimeMsInterval; + + if (delta < 2) + delta = 2; + + TimeMsDelayFinished = timeMs + (rand()%delta) + MinTimeMsInterval; + } + else + if (!Sound && (!TimeMsDelayFinished || timeMs > TimeMsDelayFinished)) + { + // play new sound + + if (SoundFileName.size()) + Sound = SoundEngine->play3D(SoundFileName.c_str(), pos, false, true, true); + + if (Sound) + { + if (MinDistance > 0 ) + Sound->setMinDistance(MinDistance); + if (MaxDistance > 0 ) + Sound->setMaxDistance(MaxDistance); + + Sound->setIsPaused(false); + } + } + } + break; + case EPM_LOOPING: + { + if (!Sound) + { + if (SoundFileName.size()) + Sound = SoundEngine->play3D(SoundFileName.c_str(), pos, true, true, true); + + if (Sound) + { + if (MinDistance > 0 ) + Sound->setMinDistance(MinDistance); + if (MaxDistance > 0 ) + Sound->setMaxDistance(MaxDistance); + + Sound->setIsPaused(false); + } + else + { + // sound could not be loaded + stop(); + } + } + } + break; + case EPM_ONCE: + { + if (PlayedCount) + { + // stop + + if (Sound && Sound->isFinished()) + { + stop(); + + if (DeleteWhenFinished) + SceneManager->addToDeletionQueue(this); + } + } + else + { + // start + + if (SoundFileName.size()) + Sound = SoundEngine->play3D(SoundFileName.c_str(), pos, false, true, true); + + if (Sound) + { + if (MinDistance > 0 ) + Sound->setMinDistance(MinDistance); + if (MaxDistance > 0 ) + Sound->setMaxDistance(MaxDistance); + + Sound->setIsPaused(false); + ++PlayedCount; + } + else + { + // sound could not be loaded + stop(); + } + } + } + break; + } +} + + +void CIrrKlangSceneNode::render() +{ + // draw scene node as billboard when debug data is visible + + if (!DebugDataVisible) + return; + + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); + + scene::ICameraSceneNode* camera = SceneManager->getActiveCamera(); + if (camera) + { + video::S3DVertex vertices[4]; + u16 indices[6]; + + indices[0] = 0; + indices[1] = 2; + indices[2] = 1; + indices[3] = 0; + indices[4] = 3; + indices[5] = 2; + + vertices[0].TCoords.set(0.0f, 1.0f); + vertices[1].TCoords.set(0.0f, 0.0f); + vertices[2].TCoords.set(1.0f, 0.0f); + vertices[3].TCoords.set(1.0f, 1.0f); + + vertices[0].Color.set(128,255,255,255); + vertices[1].Color.set(128,255,255,255); + vertices[2].Color.set(128,255,255,255); + vertices[3].Color.set(128,255,255,255); + + core::vector3df pos = getAbsolutePosition(); + core::vector3df campos = camera->getAbsolutePosition(); + core::vector3df target = camera->getTarget(); + core::vector3df up = camera->getUpVector(); + core::vector3df view = target - campos; + view.normalize(); + + core::vector3df horizontal = up.crossProduct(view); + horizontal.normalize(); + + core::vector3df vertical = horizontal.crossProduct(view); + vertical.normalize(); + + const f32 Size = 5.0f; + horizontal *= Size / 2.0f; + vertical *= Size / 2.0f; + + vertices[0].Pos = pos + horizontal + vertical; + vertices[1].Pos = pos + horizontal - vertical; + vertices[2].Pos = pos - horizontal - vertical; + vertices[3].Pos = pos - horizontal + vertical; + + view *= -1.0f; + + for (s32 i=0; i<4; ++i) + vertices[i].Normal = view; + + // draw billboard + + video::SMaterial material; + material.Lighting = false; + material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; + material.MaterialTypeParam = 255; + material.TextureLayer[0].Texture = driver->getTexture("textures/editor_defaults/default_sound.png"); + + core::matrix4 mat; + driver->setTransform(video::ETS_WORLD, mat); + driver->setMaterial(material); + + driver->drawIndexedTriangleList(vertices, 4, indices, 2); + } +} + + +const core::aabbox3d& CIrrKlangSceneNode::getBoundingBox() const +{ + return Box; +} + + +const c8* const IrrKlangPlayModeNames[] = +{ + "nothing", "random", "looping", "play_once", 0 +}; + + +//! Writes attributes of the scene node. +void CIrrKlangSceneNode::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + if (!out) + return; + + ISceneNode::serializeAttributes(out, options); + const char** soundNames = 0; + + if ( SoundEngine && options && ( options->Flags & io::EARWF_FOR_EDITOR ) ) + { + // show a list of all loaded sound files in editor + + int count = SoundEngine->getSoundSourceCount(); + soundNames = new const char*[count+3]; + + for (int i=0; igetSoundSource(i)->getName(); + + soundNames[count] = ""; + soundNames[count+1] = "