PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/torcs-1.3.3/src/modules/graphic/ssggraph/TorcsSound.cpp

#
C++ | 583 lines | 455 code | 67 blank | 61 comment | 91 complexity | 89617f9e5e06a1ce4823794467a28fc8 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0
  1. // -*- Mode: c++ -*-
  2. /***************************************************************************
  3. file : TorcsSound.cpp
  4. created : Tue Apr 5 19:57:35 CEST 2005
  5. copyright : (C) 2005 Christos Dimitrakakis, Bernhard Wymann
  6. email : dimitrak@idiap.ch
  7. version : $Id: TorcsSound.cpp,v 1.8 2005/11/18 00:20:32 olethros Exp $
  8. ***************************************************************************/
  9. /***************************************************************************
  10. * *
  11. * This program is free software; you can redistribute it and/or modify *
  12. * it under the terms of the GNU General Public License as published by *
  13. * the Free Software Foundation; either version 2 of the License, or *
  14. * (at your option) any later version. *
  15. * *
  16. ***************************************************************************/
  17. #include "TorcsSound.h"
  18. #include "SoundInterface.h"
  19. /// Set the volume \note effect not consistent across backends
  20. void TorcsSound::setVolume(float vol)
  21. {
  22. this->volume = vol;
  23. }
  24. /// Set the pitch \note Effect not consistent across backends
  25. void TorcsSound::setPitch(float pitch)
  26. {
  27. this->pitch = pitch;
  28. }
  29. /// Set the filter \note Effect not consistent across backends
  30. void TorcsSound::setLPFilter(float lp)
  31. {
  32. this->lowpass = lp;
  33. }
  34. /// Create a new PLib sound. It requires a scheduler to be set up
  35. /// and a filename to read data from.
  36. PlibTorcsSound::PlibTorcsSound(slScheduler* sched,
  37. const char* filename,
  38. int flags,
  39. bool loop) : TorcsSound (flags)
  40. {
  41. this->sched = sched;
  42. this->loop = loop;
  43. MAX_VOL = 1.0f;
  44. sample = new slSample (filename, sched);
  45. if (flags & ACTIVE_VOLUME) {
  46. volume_env = new slEnvelope(1, SL_SAMPLE_ONE_SHOT);
  47. }
  48. if (flags & ACTIVE_PITCH) {
  49. pitch_env = new slEnvelope(1, SL_SAMPLE_ONE_SHOT);
  50. }
  51. if (flags & ACTIVE_LP_FILTER) {
  52. lowpass_env = new slEnvelope(1, SL_SAMPLE_ONE_SHOT);
  53. }
  54. if (loop) {
  55. sched->loopSample (sample);
  56. }
  57. if (flags & ACTIVE_VOLUME) {
  58. sched->addSampleEnvelope (sample, 0, VOLUME_SLOT, volume_env,
  59. SL_VOLUME_ENVELOPE);
  60. }
  61. if (flags & ACTIVE_PITCH) {
  62. sched->addSampleEnvelope (sample, 0, PITCH_SLOT, pitch_env,
  63. SL_PITCH_ENVELOPE);
  64. }
  65. if (flags & ACTIVE_LP_FILTER) {
  66. sched->addSampleEnvelope(sample, 0, FILTER_SLOT, lowpass_env,
  67. SL_FILTER_ENVELOPE);
  68. }
  69. if (flags & ACTIVE_VOLUME) {
  70. volume_env->setStep(0, 0.0f, 0.0f);
  71. }
  72. if (flags & ACTIVE_PITCH) {
  73. pitch_env->setStep(0, 0.0f, 1.0f);
  74. }
  75. if (flags & ACTIVE_LP_FILTER) {
  76. lowpass_env->setStep(0, 0.0, 1.0f);
  77. }
  78. volume = 0.0f;
  79. pitch = 1.0f;
  80. lowpass = 1.0f;
  81. playing = false;
  82. paused = false;
  83. }
  84. /// Destructor.
  85. PlibTorcsSound::~PlibTorcsSound()
  86. {
  87. sched->stopSample(sample);
  88. if (flags & ACTIVE_VOLUME) {
  89. sched->addSampleEnvelope(sample, 0, VOLUME_SLOT, NULL,
  90. SL_NULL_ENVELOPE);
  91. delete volume_env;
  92. }
  93. if (flags & ACTIVE_PITCH) {
  94. sched->addSampleEnvelope(sample, 0, PITCH_SLOT, NULL,
  95. SL_NULL_ENVELOPE);
  96. delete pitch_env;
  97. }
  98. if (flags & ACTIVE_LP_FILTER) {
  99. sched->addSampleEnvelope(sample, 0, FILTER_SLOT, NULL,
  100. SL_NULL_ENVELOPE);
  101. delete lowpass_env;
  102. }
  103. delete sample;
  104. }
  105. /** Set the volume. Since plib does not support envelopes for
  106. * one-shot samples, we pre-adjust their volume
  107. */
  108. void PlibTorcsSound::setVolume(float vol)
  109. {
  110. if (vol > MAX_VOL) {
  111. vol = MAX_VOL;
  112. }
  113. this->volume = vol;
  114. if (loop==false) {
  115. sample->adjustVolume (vol);
  116. }
  117. }
  118. /// Start the sample
  119. void PlibTorcsSound::play()
  120. {
  121. start();
  122. }
  123. /// Start the sample
  124. void PlibTorcsSound::start()
  125. {
  126. // TODO: consistency check?
  127. if (loop) {
  128. if (playing == false) {
  129. playing = true;
  130. sched->loopSample (sample);
  131. }
  132. } else {
  133. playing = true;
  134. sched->playSample (sample);
  135. }
  136. }
  137. /// Stop the sample
  138. void PlibTorcsSound::stop()
  139. {
  140. if (playing == true) {
  141. playing = false;
  142. sched->stopSample (sample);
  143. }
  144. }
  145. /// Resume a paused sample.
  146. void PlibTorcsSound::resume()
  147. {
  148. sched->resumeSample (sample);
  149. paused = false;
  150. }
  151. /// Pause a sample
  152. void PlibTorcsSound::pause()
  153. {
  154. sched->pauseSample (sample);
  155. paused = true;
  156. }
  157. /** Update the plib sounds.
  158. * This should be called as often as possible from the main sound code,
  159. * probably by looping through all the sounds used.
  160. */
  161. void PlibTorcsSound::update()
  162. {
  163. if (flags & ACTIVE_VOLUME) {
  164. volume_env->setStep(0, 0.0f, volume);
  165. }
  166. if (flags & ACTIVE_PITCH) {
  167. pitch_env->setStep(0, 0.0f, pitch);
  168. }
  169. if (flags & ACTIVE_LP_FILTER) {
  170. lowpass_env->setStep(0, 0.0f, lowpass);
  171. }
  172. }
  173. /// Create a sound source
  174. SoundSource::SoundSource()
  175. {
  176. a = 0.0;
  177. f = 1.0;
  178. lp = 1.0;
  179. }
  180. /** Calculate environmental parameters for current situation.
  181. *
  182. * At the moment this
  183. */
  184. void SoundSource::update()
  185. {
  186. // Get relative speed/position vector
  187. sgVec3 u;
  188. sgVec3 p;
  189. float u_rel = 0.0f;
  190. float u_rel_src = 0.0f;
  191. float u_rel_lis = 0.0f;
  192. float p_rel = 0.0f;
  193. int i;
  194. for (i=0; i<3; i++) {
  195. u[i] = u_src[i] - u_lis[i];
  196. p[i] = p_src[i] - p_lis[i];
  197. p_rel += p[i]*p[i];
  198. }
  199. a = 1.0;
  200. f = 1.0f;
  201. lp = 1.0f;
  202. // Only the vector component on the LOV is significant
  203. // u_rel = sqrt(u_rel);
  204. p_rel = 0.01f + sqrt(p_rel);
  205. float p_cosx = p[0]/p_rel;
  206. float p_cosy = p[1]/p_rel;
  207. float p_cosz = p[2]/p_rel;
  208. float p_x_comp = u[0]*p_cosx;
  209. float p_y_comp = u[1]*p_cosy;
  210. float p_z_comp = u[2]*p_cosz;
  211. float p_x_src = u_src[0]*p_cosx;
  212. float p_y_src = u_src[1]*p_cosy;
  213. float p_z_src = u_src[2]*p_cosz;
  214. float p_x_lis = u_lis[0]*p_cosx;
  215. float p_y_lis = u_lis[1]*p_cosy;
  216. float p_z_lis = u_lis[2]*p_cosz;
  217. u_rel = (p_y_comp + p_x_comp + p_z_comp);
  218. u_rel_src = (p_y_src + p_x_src + p_z_src);
  219. u_rel_lis = (p_y_lis + p_x_lis + p_z_lis);
  220. if (fabs(u_rel)>=0.9f*SPEED_OF_SOUND) {
  221. // Cut-off sound when relative speed approaches speed of sound.
  222. a = 0.0f;
  223. f = 1.0f;
  224. lp = 1.0f;
  225. } else {
  226. // attenuate and filter sound with distance
  227. // and shift pitch with speed
  228. float ref = 5.0f;
  229. float rolloff = 0.5f;
  230. float atten = ref / ( ref + rolloff * (p_rel - ref));
  231. //f = SPEED_OF_SOUND/(SPEED_OF_SOUND+u_rel);
  232. f = (SPEED_OF_SOUND - u_rel_src)/(SPEED_OF_SOUND - u_rel_lis);
  233. a = atten;
  234. float atten_filter = MIN (atten, 1.0f);
  235. lp = exp(atten_filter - 1.0f);
  236. }
  237. }
  238. /** Set source position and velocity.
  239. */
  240. void SoundSource::setSource(sgVec3 p, sgVec3 u)
  241. {
  242. for (int i=0; i<3; i++) {
  243. p_src[i] = p[i];
  244. u_src[i] = u[i];
  245. }
  246. }
  247. /** Set listener position and velocity.
  248. */
  249. void SoundSource::setListener (sgVec3 p, sgVec3 u)
  250. {
  251. for (int i=0; i<3; i++) {
  252. p_lis[i] = p[i];
  253. u_lis[i] = u[i];
  254. }
  255. }
  256. /** Create a new torcs sound
  257. *
  258. *
  259. */
  260. OpenalTorcsSound::OpenalTorcsSound(const char* filename, OpenalSoundInterface* sitf, int flags, bool loop, bool static_pool)
  261. {
  262. this->loop = loop;
  263. this->flags = flags;
  264. this->static_pool = static_pool;
  265. volume = 0.0f;
  266. pitch = 1.0f;
  267. lowpass = 1.0f;
  268. poolindex = -1;
  269. itf = sitf;
  270. MAX_DISTANCE = 10000.0f;
  271. MAX_DISTANCE_LOW = 5.0f;
  272. REFERENCE_DISTANCE = 5.0f;
  273. ROLLOFF_FACTOR = 0.5f;
  274. playing = false;
  275. paused = false;
  276. int i;
  277. for (i = 0; i<3; i++) {
  278. source_position[i] = 0.0f;
  279. source_velocity[i] = 0.0f;
  280. zeroes[i] = 0.0f;
  281. }
  282. //printf("SOUND, create source: %s -> %s\n", filename, (static_pool == true) ? "static" : "dynamic");
  283. int error = alGetError();
  284. if (error != AL_NO_ERROR) {
  285. printf("Uncatched OpenAL Error on entry: %d with file %s\n", error, filename);
  286. }
  287. alGenBuffers (1, &buffer);
  288. error = alGetError();
  289. if (error != AL_NO_ERROR) {
  290. printf("OpenAL Error: %d, alGenBuffers failed %s\n", error, filename);
  291. is_enabled = false;
  292. return;
  293. }
  294. ALvoid *wave = NULL;
  295. ALsizei size;
  296. ALsizei freq;
  297. ALenum format;
  298. ALboolean srcloop;
  299. alutLoadWAVFile((ALbyte *) filename, &format, &wave, &size, &freq, &srcloop);
  300. error = alGetError();
  301. if (error != AL_NO_ERROR) {
  302. printf("OpenAL Error: %d, could not load %s\n", error, filename);
  303. if (alIsBuffer(buffer)) {
  304. alDeleteBuffers(1, &buffer);
  305. alGetError();
  306. }
  307. is_enabled = false;
  308. return;
  309. }
  310. alBufferData (buffer, format, wave, size, freq);
  311. error = alGetError();
  312. if (error != AL_NO_ERROR) {
  313. printf("OpenAL Error: %d, alBufferData %s\n", error, filename);
  314. if (alIsBuffer(buffer)) {
  315. alDeleteBuffers(1, &buffer);
  316. alGetError();
  317. }
  318. is_enabled = false;
  319. return;
  320. }
  321. alutUnloadWAV(format, wave, size, freq);
  322. error = alGetError();
  323. if (error != AL_NO_ERROR) {
  324. printf("OpenAL Error: %d, alutUnloadWAV %s\n", error, filename);
  325. }
  326. if (!static_pool) {
  327. is_enabled = true;
  328. return;
  329. }
  330. if (!sitf->getStaticSource(&source)) {
  331. is_enabled = false;
  332. printf(" No static sources left: %s\n", filename);
  333. if (alIsBuffer(buffer)) {
  334. alDeleteBuffers(1, &buffer);
  335. alGetError();
  336. }
  337. return;
  338. } else {
  339. is_enabled = true;
  340. }
  341. alSourcefv (source, AL_POSITION, source_position);
  342. error = alGetError();
  343. if (error != AL_NO_ERROR) {
  344. printf("OpenAL Error: %d, alSourcefv AL_POSITION %s\n", error, filename);
  345. }
  346. alSourcefv (source, AL_VELOCITY, source_velocity);
  347. error = alGetError();
  348. if (error != AL_NO_ERROR) {
  349. printf("OpenAL Error: %d, alSourcefv AL_VELOCITY %s\n", error, filename);
  350. }
  351. alSourcei (source, AL_BUFFER, buffer);
  352. error = alGetError();
  353. if (error != AL_NO_ERROR) {
  354. printf("OpenAL Error: %d, alSourcei AL_BUFFER %s\n", error, filename);
  355. }
  356. alSourcei (source, AL_LOOPING, loop);
  357. if (error != AL_NO_ERROR) {
  358. printf("OpenAL Error: %d, alSourcei AL_LOOPING %s\n", error, filename);
  359. }
  360. alSourcef (source, AL_MAX_DISTANCE, MAX_DISTANCE);
  361. if (error != AL_NO_ERROR) {
  362. printf("OpenAL Error: %d, alSourcef AL_MAX_DISTANCE %s\n", error, filename);
  363. }
  364. alSourcef (source, AL_REFERENCE_DISTANCE, REFERENCE_DISTANCE);
  365. if (error != AL_NO_ERROR) {
  366. printf("OpenAL Error: %d, alSourcef AL_REFERENCE_DISTANCE %s\n", error, filename);
  367. }
  368. alSourcef (source, AL_ROLLOFF_FACTOR, ROLLOFF_FACTOR);
  369. if (error != AL_NO_ERROR) {
  370. printf("OpenAL Error: %d, alSourcef AL_ROLLOFF_FACTOR %s\n", error, filename);
  371. }
  372. alSourcef (source, AL_GAIN, 0.0f);
  373. if (error != AL_NO_ERROR) {
  374. printf("OpenAL Error: %d, alSourcef AL_GAIN %s\n", error, filename);
  375. }
  376. }
  377. OpenalTorcsSound::~OpenalTorcsSound()
  378. {
  379. if (alIsSource(source)) {
  380. alSourceStop (source);
  381. alDeleteSources(1, &source);
  382. }
  383. if (alIsBuffer(buffer)) {
  384. alDeleteBuffers(1, &buffer);
  385. }
  386. }
  387. void OpenalTorcsSound::setVolume (float vol)
  388. {
  389. this->volume = vol;
  390. }
  391. void OpenalTorcsSound::setPitch(float pitch)
  392. {
  393. this->pitch = pitch;
  394. }
  395. void OpenalTorcsSound::setLPFilter(float lp)
  396. {
  397. this->lowpass = lp;
  398. }
  399. void OpenalTorcsSound::setReferenceDistance(float dist)
  400. {
  401. if (static_pool) {
  402. if (is_enabled) {
  403. alSourcef (source, AL_REFERENCE_DISTANCE, dist);
  404. }
  405. } else {
  406. if (itf->getSourcePool()->isSourceActive(this, &poolindex)) {
  407. alSourcef (source, AL_REFERENCE_DISTANCE, dist);
  408. REFERENCE_DISTANCE = dist;
  409. }
  410. }
  411. }
  412. void OpenalTorcsSound::setSource (sgVec3 p, sgVec3 u)
  413. {
  414. for (int i=0; i<3; i++) {
  415. source_position[i] = p[i];
  416. source_velocity[i] = u[i];
  417. }
  418. }
  419. void OpenalTorcsSound::getSource(sgVec3 p, sgVec3 u)
  420. {
  421. for (int i=0; i<3; i++) {
  422. p[i] = source_position[i];
  423. u[i] = source_velocity[i];
  424. }
  425. }
  426. void OpenalTorcsSound::play()
  427. {
  428. start();
  429. }
  430. void OpenalTorcsSound::start()
  431. {
  432. if (static_pool) {
  433. if (is_enabled) {
  434. if (playing==false) {
  435. if (loop) {
  436. playing = true;
  437. }
  438. alSourcePlay (source);
  439. }
  440. }
  441. } else {
  442. // shared source.
  443. bool needs_init;
  444. if (itf->getSourcePool()->getSource(this, &source, &needs_init, &poolindex)) {
  445. if (needs_init) {
  446. // Setup source.
  447. alSourcefv (source, AL_POSITION, source_position);
  448. alSourcefv (source, AL_VELOCITY, source_velocity);
  449. alSourcei (source, AL_BUFFER, buffer);
  450. alSourcei (source, AL_LOOPING, loop);
  451. alSourcef (source, AL_MAX_DISTANCE, MAX_DISTANCE);
  452. alSourcef (source, AL_REFERENCE_DISTANCE, REFERENCE_DISTANCE);
  453. alSourcef (source, AL_ROLLOFF_FACTOR, ROLLOFF_FACTOR);
  454. alSourcef (source, AL_GAIN, 0.0f);
  455. }
  456. // play
  457. if (playing==false) {
  458. if (loop) {
  459. playing = true;
  460. }
  461. alSourcePlay (source);
  462. }
  463. }
  464. }
  465. }
  466. void OpenalTorcsSound::stop()
  467. {
  468. if (static_pool) {
  469. if (is_enabled) {
  470. if (playing==true) {
  471. playing = false;
  472. alSourceStop (source);
  473. }
  474. }
  475. } else {
  476. // Shared source.
  477. if (itf->getSourcePool()->releaseSource(this, &poolindex)) {
  478. if (playing==true) {
  479. playing = false;
  480. alSourceStop (source);
  481. }
  482. }
  483. }
  484. }
  485. void OpenalTorcsSound::resume()
  486. {
  487. if (paused==true) {
  488. paused = false;
  489. }
  490. }
  491. void OpenalTorcsSound::pause()
  492. {
  493. if (paused==false) {
  494. paused = true;
  495. }
  496. }
  497. void OpenalTorcsSound::update ()
  498. {
  499. ALfloat zero_velocity[3] = {0.0f, 0.0f, 0.0f};
  500. if (static_pool) {
  501. if (is_enabled) {
  502. alSourcefv (source, AL_POSITION, source_position);
  503. alSourcefv (source, AL_VELOCITY, zero_velocity);
  504. alSourcef (source, AL_PITCH, pitch);
  505. alSourcef (source, AL_GAIN, volume);
  506. }
  507. } else {
  508. if (itf->getSourcePool()->isSourceActive(this, &poolindex)) {
  509. alSourcefv (source, AL_POSITION, source_position);
  510. alSourcefv (source, AL_VELOCITY, zero_velocity);
  511. alSourcef (source, AL_PITCH, pitch);
  512. alSourcef (source, AL_GAIN, volume);
  513. }
  514. }
  515. }