PolySound.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. /*
  2. * PolySound.cpp
  3. * Poly
  4. *
  5. * Created by Ivan Safrin on 3/15/09.
  6. * Copyright 2009 __MyCompanyName__. All rights reserved.
  7. *
  8. */
  9. #include "PolySound.h"
  10. using namespace Polycode;
  11. size_t custom_readfunc(void *ptr, size_t size, size_t nmemb, void *datasource) {
  12. OSFILE *file = (OSFILE*) datasource;
  13. return OSBasics::read(ptr, size, nmemb, file);
  14. }
  15. int custom_seekfunc(void *datasource, ogg_int64_t offset, int whence){
  16. OSFILE *file = (OSFILE*) datasource;
  17. return OSBasics::seek(file, offset, whence);
  18. }
  19. int custom_closefunc(void *datasource) {
  20. OSFILE *file = (OSFILE*) datasource;
  21. return OSBasics::close(file);
  22. }
  23. long custom_tellfunc(void *datasource) {
  24. OSFILE *file = (OSFILE*) datasource;
  25. return OSBasics::tell(file);
  26. }
  27. Sound::Sound(String fileName) {
  28. String extension;
  29. size_t found;
  30. found=fileName.rfind(".");
  31. if (found!=string::npos) {
  32. extension = fileName.substr(found+1);
  33. } else {
  34. extension = "";
  35. }
  36. ALuint buffer;
  37. if(extension == "wav" || extension == "WAV") {
  38. buffer = loadWAV(fileName);
  39. } else if(extension == "ogg" || extension == "OGG") {
  40. buffer = loadOGG(fileName);
  41. }
  42. soundSource = GenSource(buffer);
  43. }
  44. Sound::~Sound() {
  45. Logger::log("destroying sound...\n");
  46. alDeleteSources(1,&soundSource);
  47. }
  48. void Sound::soundCheck(bool result, String err) {
  49. if(!result)
  50. soundError(err);
  51. }
  52. void Sound::soundError(String err) {
  53. Logger::log("SOUND ERROR: %s\n", err.c_str());
  54. }
  55. unsigned long Sound::readByte32(const unsigned char buffer[4]) {
  56. #if TAU_BIG_ENDIAN
  57. return (buffer[0] << 24) + (buffer[1] << 16) + (buffer[2] << 8) + buffer[3];
  58. #else
  59. return (buffer[3] << 24) + (buffer[2] << 16) + (buffer[1] << 8) + buffer[0];
  60. #endif
  61. }
  62. unsigned short Sound::readByte16(const unsigned char buffer[2]) {
  63. #if TAU_BIG_ENDIAN
  64. return (buffer[0] << 8) + buffer[1];
  65. #else
  66. return (buffer[1] << 8) + buffer[0];
  67. #endif
  68. }
  69. void Sound::Play(bool once) {
  70. if(once) {
  71. alSourcei(soundSource, AL_LOOPING, AL_FALSE);
  72. } else {
  73. alSourcei(soundSource, AL_LOOPING, AL_TRUE);
  74. }
  75. alSourcePlay(soundSource);
  76. }
  77. void Sound::checkALError(String operation) {
  78. ALenum error = alGetError();
  79. if(error != AL_NO_ERROR) {
  80. switch(error) {
  81. case AL_NO_ERROR:
  82. soundError(operation + ": " +ALNoErrorStr);
  83. break;
  84. case AL_INVALID_NAME:
  85. soundError(operation +": " + ALInvalidNameStr);
  86. break;
  87. case AL_INVALID_ENUM:
  88. soundError(operation + ": " +ALInvalidEnumStr);
  89. break;
  90. case AL_INVALID_VALUE:
  91. soundError(operation + ": " +ALInvalidValueStr);
  92. break;
  93. case AL_INVALID_OPERATION:
  94. soundError(operation + ": " +ALInvalidOpStr);
  95. break;
  96. case AL_OUT_OF_MEMORY:
  97. soundError(operation + ": " +ALOutOfMemoryStr);
  98. break;
  99. default:
  100. soundError(operation + ": " +ALOtherErrorStr);
  101. break;
  102. }
  103. }
  104. }
  105. void Sound::Stop() {
  106. alSourceStop(soundSource);
  107. }
  108. ALuint Sound::GenSource() {
  109. ALuint source;
  110. bool looping = false;
  111. ALfloat sourcePos[] = {0.0, 0.0, 0.0};
  112. ALfloat sourceVel[] = {0.0, 0.0, 0.0};
  113. alGetError();
  114. alGenSources(1, &source);
  115. checkALError("Generating sources");
  116. alSourcef(source, AL_PITCH, 1.0);
  117. alSourcef(source, AL_GAIN, 1.0);
  118. alSourcefv(source, AL_POSITION, sourcePos);
  119. alSourcefv(source, AL_VELOCITY, sourceVel);
  120. alSourcei(source, AL_LOOPING, looping);
  121. checkALError("Setting source properties");
  122. return source;
  123. }
  124. ALuint Sound::GenSource(ALuint buffer) {
  125. alGetError();
  126. ALuint source = GenSource();
  127. alSourcei(source, AL_BUFFER, buffer);
  128. checkALError("Setting source buffer");
  129. return source;
  130. }
  131. ALuint Sound::loadOGG(String fileName) {
  132. vector<char> buffer;
  133. ALuint bufferID = AL_NONE;
  134. alGenBuffers(1, &bufferID);
  135. int endian = 0; // 0 for Little-Endian, 1 for Big-Endian
  136. int bitStream;
  137. long bytes;
  138. char array[BUFFER_SIZE]; // Local fixed size array
  139. OSFILE *f;
  140. ALenum format;
  141. ALsizei freq;
  142. // Open for binary reading
  143. f = OSBasics::open(fileName.c_str(), "rb");
  144. if(!f) {
  145. soundError("Error loading OGG file!\n");
  146. return bufferID;
  147. }
  148. vorbis_info *pInfo;
  149. OggVorbis_File oggFile;
  150. ov_callbacks callbacks;
  151. callbacks.read_func = custom_readfunc;
  152. callbacks.seek_func = custom_seekfunc;
  153. callbacks.close_func = custom_closefunc;
  154. callbacks.tell_func = custom_tellfunc;
  155. ov_open_callbacks( (void*)f, &oggFile, NULL, 0, callbacks);
  156. // ov_open(f, &oggFile, NULL, 0);
  157. // Get some information about the OGG file
  158. pInfo = ov_info(&oggFile, -1);
  159. // Check the number of channels... always use 16-bit samples
  160. if (pInfo->channels == 1)
  161. format = AL_FORMAT_MONO16;
  162. else
  163. format = AL_FORMAT_STEREO16;
  164. // end if
  165. // The frequency of the sampling rate
  166. freq = pInfo->rate;
  167. do {
  168. // Read up to a buffer's worth of decoded sound data
  169. bytes = ov_read(&oggFile, array, BUFFER_SIZE, endian, 2, 1, &bitStream);
  170. // Append to end of buffer
  171. buffer.insert(buffer.end(), array, array + bytes);
  172. } while (bytes > 0);
  173. ov_clear(&oggFile);
  174. alBufferData(bufferID, format, &buffer[0], static_cast<ALsizei>(buffer.size()), freq);
  175. return bufferID;
  176. }
  177. ALuint Sound::loadWAV(String fileName) {
  178. long bytes;
  179. vector <char> data;
  180. ALenum format;
  181. ALsizei freq;
  182. // Local resources
  183. OSFILE *f = NULL;
  184. char *array = NULL;
  185. ALuint buffer = AL_NONE;
  186. alGetError();
  187. // Open for binary reading
  188. f = OSBasics::open(fileName.c_str(), "rb");
  189. if (!f)
  190. soundError("LoadWav: Could not load wav from " + fileName);
  191. // buffers
  192. char magic[5];
  193. magic[4] = '\0';
  194. unsigned char buffer32[4];
  195. unsigned char buffer16[2];
  196. // check magic
  197. soundCheck(OSBasics::read(magic,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  198. soundCheck(String(magic) == "RIFF", "LoadWav: Wrong wav file format. This file is not a .wav file (no RIFF magic): "+ fileName );
  199. // skip 4 bytes (file size)
  200. OSBasics::seek(f,4,SEEK_CUR);
  201. // check file format
  202. soundCheck(OSBasics::read(magic,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  203. soundCheck(String(magic) == "WAVE", "LoadWav: Wrong wav file format. This file is not a .wav file (no WAVE format): "+ fileName );
  204. // check 'fmt ' sub chunk (1)
  205. soundCheck(OSBasics::read(magic,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  206. soundCheck(String(magic) == "fmt ", "LoadWav: Wrong wav file format. This file is not a .wav file (no 'fmt ' subchunk): "+ fileName );
  207. // read (1)'s size
  208. soundCheck(OSBasics::read(buffer32,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  209. unsigned long subChunk1Size = readByte32(buffer32);
  210. soundCheck(subChunk1Size >= 16, "Wrong wav file format. This file is not a .wav file ('fmt ' chunk too small, truncated file?): "+ fileName );
  211. // check PCM audio format
  212. soundCheck(OSBasics::read(buffer16,2,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  213. unsigned short audioFormat = readByte16(buffer16);
  214. soundCheck(audioFormat == 1, "LoadWav: Wrong wav file format. This file is not a .wav file (audio format is not PCM): "+ fileName );
  215. // read number of channels
  216. soundCheck(OSBasics::read(buffer16,2,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  217. unsigned short channels = readByte16(buffer16);
  218. // read frequency (sample rate)
  219. soundCheck(OSBasics::read(buffer32,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  220. unsigned long frequency = readByte32(buffer32);
  221. // skip 6 bytes (Byte rate (4), Block align (2))
  222. OSBasics::seek(f,6,SEEK_CUR);
  223. // read bits per sample
  224. soundCheck(OSBasics::read(buffer16,2,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  225. unsigned short bps = readByte16(buffer16);
  226. if (channels == 1)
  227. format = (bps == 8) ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16;
  228. else
  229. format = (bps == 8) ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16;
  230. // check 'data' sub chunk (2)
  231. soundCheck(OSBasics::read(magic,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  232. soundCheck(String(magic) == "data", "LoadWav: Wrong wav file format. This file is not a .wav file (no data subchunk): "+ fileName );
  233. soundCheck(OSBasics::read(buffer32,4,1,f) == 1, "LoadWav: Cannot read wav file "+ fileName );
  234. unsigned long subChunk2Size = readByte32(buffer32);
  235. // The frequency of the sampling rate
  236. freq = frequency;
  237. soundCheck(sizeof(freq) == sizeof(frequency), "LoadWav: freq and frequency different sizes");
  238. array = new char[BUFFER_SIZE];
  239. while (data.size() != subChunk2Size) {
  240. // Read up to a buffer's worth of decoded sound data
  241. bytes = OSBasics::read(array, 1, BUFFER_SIZE, f);
  242. if (bytes <= 0)
  243. break;
  244. if (data.size() + bytes > subChunk2Size)
  245. bytes = subChunk2Size - data.size();
  246. // Append to end of buffer
  247. data.insert(data.end(), array, array + bytes);
  248. };
  249. delete []array;
  250. array = NULL;
  251. OSBasics::close(f);
  252. f = NULL;
  253. alGenBuffers(1, &buffer);
  254. soundCheck(alGetError() == AL_NO_ERROR, "LoadWav: Could not generate buffer");
  255. soundCheck(AL_NONE != buffer, "LoadWav: Could not generate buffer");
  256. alBufferData(buffer, format, &data[0], data.size(), freq);
  257. soundCheck(alGetError() == AL_NO_ERROR, "LoadWav: Could not load buffer data");
  258. return buffer;
  259. // if (buffer)
  260. // if (alIsBuffer(buffer) == AL_TRUE)
  261. // alDeleteBuffers(1, &buffer);
  262. //
  263. // if (array)
  264. // delete []array;
  265. //
  266. // if (f)
  267. // OSBasics::close(f);
  268. //
  269. // throw (e);
  270. }