Sound.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. //
  2. // Urho3D Engine
  3. // Copyright (c) 2008-2011 Lasse Öörni
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a copy
  6. // of this software and associated documentation files (the "Software"), to deal
  7. // in the Software without restriction, including without limitation the rights
  8. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. // copies of the Software, and to permit persons to whom the Software is
  10. // furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. // THE SOFTWARE.
  22. //
  23. #include "Precompiled.h"
  24. #include "Profiler.h"
  25. #include "ResourceCache.h"
  26. #include "Sound.h"
  27. #include "XMLFile.h"
  28. #include <cstring>
  29. #include <stb_vorbis.h>
  30. #include "DebugNew.h"
  31. //! WAV format header
  32. struct WavHeader
  33. {
  34. unsigned char mRiffText[4];
  35. unsigned mTotalLength;
  36. unsigned char mWaveText[4];
  37. unsigned char mFormatText[4];
  38. unsigned mFormatLength;
  39. unsigned short mFormat;
  40. unsigned short mChannels;
  41. unsigned mFrequency;
  42. unsigned mAvgBytes;
  43. unsigned short mBlockAlign;
  44. unsigned short mBits;
  45. unsigned char mDataText[4];
  46. unsigned mDataLength;
  47. };
  48. static const unsigned IP_SAFETY = 4;
  49. Sound::Sound(const std::string& name) :
  50. Resource(name),
  51. mRepeat(0),
  52. mEnd(0),
  53. mFrequency(44100),
  54. mLooped(false),
  55. mSixteenBit(false),
  56. mStereo(false),
  57. mCompressed(false),
  58. mCompressedLength(0.0f)
  59. {
  60. }
  61. Sound::~Sound()
  62. {
  63. }
  64. void Sound::load(Deserializer& source, ResourceCache* cache)
  65. {
  66. PROFILE(Sound_Load);
  67. if (getExtension(source.getName()) == ".ogg")
  68. loadOggVorbis(source);
  69. else if (getExtension(source.getName()) == ".wav")
  70. loadWav(source);
  71. else
  72. loadRaw(source);
  73. // Load optional parameters
  74. loadParameters(cache);
  75. }
  76. void Sound::loadOggVorbis(Deserializer& source)
  77. {
  78. unsigned dataSize = source.getSize();
  79. SharedArrayPtr<signed char> data(new signed char[dataSize]);
  80. source.read(data.getPtr(), dataSize);
  81. // Check for validity of data
  82. int error;
  83. stb_vorbis* vorbis = stb_vorbis_open_memory((unsigned char*)data.getPtr(), dataSize, &error, 0);
  84. if (!vorbis)
  85. EXCEPTION("Could not read Ogg Vorbis data from " + source.getName());
  86. // Store length, frequency and stereo flag
  87. stb_vorbis_info info = stb_vorbis_get_info(vorbis);
  88. mCompressedLength = stb_vorbis_stream_length_in_seconds(vorbis);
  89. mFrequency = info.sample_rate;
  90. mStereo = info.channels > 1;
  91. stb_vorbis_close(vorbis);
  92. mData = data;
  93. mDataSize = dataSize;
  94. mSixteenBit = true;
  95. mCompressed = true;
  96. setMemoryUse(dataSize);
  97. }
  98. void Sound::loadWav(Deserializer& source)
  99. {
  100. WavHeader header;
  101. // Try to open
  102. memset(&header, 0, sizeof header);
  103. source.read(&header.mRiffText, 4);
  104. header.mTotalLength = source.readUInt();
  105. source.read(&header.mWaveText, 4);
  106. if ((memcmp("RIFF", header.mRiffText, 4)) || (memcmp("WAVE", header.mWaveText, 4)))
  107. EXCEPTION("Could not read WAV data from " + source.getName());
  108. // Search for the FORMAT chunk
  109. for (;;)
  110. {
  111. source.read(&header.mFormatText, 4);
  112. header.mFormatLength = source.readUInt();
  113. if (!memcmp("fmt ", &header.mFormatText, 4))
  114. break;
  115. source.seek(source.getPosition() + header.mFormatLength);
  116. if ((!header.mFormatLength) || (source.getPosition() >= source.getSize()))
  117. EXCEPTION("Could not read WAV data from " + source.getName());
  118. }
  119. // Read the FORMAT chunk
  120. header.mFormat = source.readUShort();
  121. header.mChannels = source.readUShort();
  122. header.mFrequency = source.readUInt();
  123. header.mAvgBytes = source.readUInt();
  124. header.mBlockAlign = source.readUShort();
  125. header.mBits = source.readUShort();
  126. // Skip data if the format chunk was bigger than what we use
  127. source.seek(source.getPosition() + header.mFormatLength - 16);
  128. // Check for correct format
  129. if (header.mFormat != 1)
  130. EXCEPTION("Could not read WAV data from " + source.getName());
  131. // Search for the DATA chunk
  132. for (;;)
  133. {
  134. source.read(&header.mDataText, 4);
  135. header.mDataLength = source.readUInt();
  136. if (!memcmp("data", &header.mDataText, 4))
  137. break;
  138. source.seek(source.getPosition() + header.mDataLength);
  139. if ((!header.mDataLength) || (source.getPosition() >= source.getSize()))
  140. EXCEPTION("Could not read WAV data from " + source.getName());
  141. }
  142. // Allocate sound and load audio data
  143. unsigned length = header.mDataLength;
  144. setSize(length);
  145. setFormat(header.mFrequency, header.mBits == 16, header.mChannels == 2);
  146. source.read(mData.getPtr(), length);
  147. // Convert 8-bit audio to signed
  148. if (!mSixteenBit)
  149. {
  150. for (unsigned i = 0; i < length; ++i)
  151. mData[i] -= 128;
  152. }
  153. }
  154. void Sound::loadRaw(Deserializer& source)
  155. {
  156. unsigned dataSize = source.getSize();
  157. setSize(dataSize);
  158. source.read(mData.getPtr(), dataSize);
  159. }
  160. void Sound::setSize(unsigned dataSize)
  161. {
  162. if (!dataSize)
  163. return;
  164. mData = new signed char[dataSize + IP_SAFETY];
  165. mDataSize = dataSize;
  166. mCompressed = false;
  167. setOneshot();
  168. setMemoryUse(dataSize + IP_SAFETY);
  169. }
  170. void Sound::setData(const void* data, unsigned dataSize)
  171. {
  172. if (!dataSize)
  173. return;
  174. setSize(dataSize);
  175. memcpy(mData.getPtr(), data, dataSize);
  176. }
  177. void Sound::setFormat(unsigned frequency, bool sixteenBit, bool stereo)
  178. {
  179. mFrequency = frequency;
  180. mSixteenBit = sixteenBit;
  181. mStereo = stereo;
  182. mCompressed = false;
  183. }
  184. void Sound::setOneshot()
  185. {
  186. if (!mCompressed)
  187. {
  188. mEnd = mData.getPtr() + mDataSize;
  189. mLooped = false;
  190. fixInterpolation();
  191. }
  192. else
  193. mLooped = false;
  194. }
  195. void Sound::setLooped()
  196. {
  197. setLoop(0, mDataSize);
  198. }
  199. void Sound::setLoop(unsigned repeatOffset, unsigned endOffset)
  200. {
  201. if (!mCompressed)
  202. {
  203. if (repeatOffset > mDataSize)
  204. repeatOffset = mDataSize;
  205. if (endOffset > mDataSize)
  206. endOffset = mDataSize;
  207. // Align repeat and end on sample boundaries
  208. int sampleSize = getSampleSize();
  209. repeatOffset &= -sampleSize;
  210. endOffset &= -sampleSize;
  211. mRepeat = mData.getPtr() + repeatOffset;
  212. mEnd = mData.getPtr() + endOffset;
  213. mLooped = true;
  214. fixInterpolation();
  215. }
  216. else
  217. mLooped = true;
  218. }
  219. void Sound::fixInterpolation()
  220. {
  221. if (!mData)
  222. return;
  223. // If looped, copy loop start to loop end. If oneshot, insert silence to end
  224. if (mLooped)
  225. {
  226. for (unsigned i = 0; i < IP_SAFETY; ++i)
  227. mEnd[i] = mRepeat[i];
  228. }
  229. else
  230. {
  231. for (unsigned i = 0; i < IP_SAFETY; ++i)
  232. mEnd[i] = 0;
  233. }
  234. }
  235. void* Sound::allocateDecoder()
  236. {
  237. if (!mCompressed)
  238. return 0;
  239. int error;
  240. stb_vorbis* vorbis = stb_vorbis_open_memory((unsigned char*)mData.getPtr(), mDataSize, &error, 0);
  241. return vorbis;
  242. }
  243. unsigned Sound::decode(void* decoder, signed char* dest, unsigned bytes)
  244. {
  245. if (!decoder)
  246. return 0;
  247. unsigned channels = mStereo ? 2 : 1;
  248. stb_vorbis* vorbis = static_cast<stb_vorbis*>(decoder);
  249. unsigned outSamples = stb_vorbis_get_samples_short_interleaved(vorbis, channels, (short*)dest, bytes >> 1);
  250. return (outSamples * channels) << 1;
  251. }
  252. void Sound::rewindDecoder(void* decoder)
  253. {
  254. if (!decoder)
  255. return;
  256. stb_vorbis* vorbis = static_cast<stb_vorbis*>(decoder);
  257. stb_vorbis_seek_start(vorbis);
  258. }
  259. void Sound::freeDecoder(void* decoder)
  260. {
  261. if (!decoder)
  262. return;
  263. stb_vorbis* vorbis = static_cast<stb_vorbis*>(decoder);
  264. stb_vorbis_close(vorbis);
  265. }
  266. float Sound::getLength() const
  267. {
  268. if (!mCompressed)
  269. {
  270. if (!mFrequency)
  271. return 0.0f;
  272. else
  273. return ((float)mDataSize) / getSampleSize() / mFrequency;
  274. }
  275. else
  276. return mCompressedLength;
  277. }
  278. unsigned Sound::getSampleSize() const
  279. {
  280. unsigned size = 1;
  281. if (mSixteenBit)
  282. size <<= 1;
  283. if (mStereo)
  284. size <<= 1;
  285. return size;
  286. }
  287. void Sound::loadParameters(ResourceCache* cache)
  288. {
  289. if (!cache)
  290. return;
  291. std::string soundPath, soundName, soundExt;
  292. splitPath(getName(), soundPath, soundName, soundExt);
  293. std::string xmlName = soundPath + soundName + ".xml";
  294. if (!cache->exists(xmlName))
  295. return;
  296. XMLFile* xml = cache->getResource<XMLFile>(xmlName);
  297. XMLElement rootElem = xml->getRootElement();
  298. XMLElement paramElem = rootElem.getChildElement("");
  299. while (paramElem)
  300. {
  301. std::string name = paramElem.getName();
  302. if ((name == "format") && (!mCompressed))
  303. {
  304. if (paramElem.hasAttribute("frequency"))
  305. mFrequency = paramElem.getInt("frequency");
  306. if (paramElem.hasAttribute("sixteenbit"))
  307. mSixteenBit = paramElem.getBool("sixteenbit");
  308. if (paramElem.hasAttribute("16bit"))
  309. mSixteenBit = paramElem.getBool("16bit");
  310. if (paramElem.hasAttribute("stereo"))
  311. mStereo = paramElem.getBool("stereo");
  312. }
  313. if (name == "loop")
  314. {
  315. if (paramElem.hasAttribute("enable"))
  316. {
  317. if (paramElem.getBool("enable"))
  318. setLooped();
  319. else
  320. setOneshot();
  321. }
  322. if ((paramElem.hasAttribute("start")) && (paramElem.hasAttribute("end")))
  323. setLoop(paramElem.getInt("start"), paramElem.getInt("end"));
  324. }
  325. paramElem = paramElem.getNextElement();
  326. }
  327. }