Sound.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. /******************************************************************************
  2. Use 'SoundVolume' to set volume for different sound groups
  3. Use 'SoundPlay' to play custom sounds
  4. Use 'Sound' to play custom sounds and control them later
  5. Use 'Listener' to set 3D listener parameters which receives 3D sounds
  6. /******************************************************************************/
  7. enum VOLUME_GROUP : Byte // Sound Volume Group
  8. {
  9. VOLUME_FX , // Sound Effects
  10. VOLUME_MUSIC , // Music
  11. VOLUME_AMBIENT, // Ambient Surroundings
  12. VOLUME_VOICE , // Voices
  13. VOLUME_UI , // User Interface
  14. VOLUME_NUM , // number of volume groups
  15. };
  16. /******************************************************************************/
  17. struct SoundVolumeClass
  18. {
  19. void fx (Flt v); Flt fx ()C {return _v[VOLUME_FX ];} // set/get fx volume (0..1)
  20. void music (Flt v); Flt music ()C {return _v[VOLUME_MUSIC ];} // set/get music volume (0..1)
  21. void ambient(Flt v); Flt ambient()C {return _v[VOLUME_AMBIENT];} // set/get ambient volume (0..1)
  22. void voice (Flt v); Flt voice ()C {return _v[VOLUME_VOICE ];} // set/get voice volume (0..1)
  23. void ui (Flt v); Flt ui ()C {return _v[VOLUME_UI ];} // set/get UI volume (0..1)
  24. void global (Flt v); Flt global ()C {return _v[VOLUME_NUM ];} // set/get global volume (0..1)
  25. #if EE_PRIVATE
  26. void update(); // update sound volumes
  27. #endif
  28. #if !EE_PRIVATE
  29. private:
  30. #endif
  31. Flt _v[VOLUME_NUM+1]; // +1 to make room for global
  32. SoundVolumeClass();
  33. }extern
  34. SoundVolume; // Main Sound Volume Control
  35. /******************************************************************************/
  36. struct ListenerClass
  37. {
  38. #if EE_PRIVATE
  39. Bool create();
  40. UInt updateNoLock(); // update listener
  41. void commitNoLock(); // update all 3D sounds parameters, only after this call all 3D sound changes are updated, this should be called once per frame
  42. #endif
  43. // get
  44. C Vec& pos ()C {return _orn.pos ;} // get listener position
  45. C Vec& dir ()C {return _orn.dir ;} // get listener forward direction
  46. C Vec& up ()C {return _orn.perp ;} // get listener up direction
  47. Vec right()C {return _orn.cross();} // get listener right direction
  48. C Vec& vel ()C {return _vel ;} // get listener velocity
  49. // set
  50. ListenerClass& pos(C Vec &pos ); // set listener position
  51. ListenerClass& orn(C Vec &dir, C Vec &up=Vec(0, 1, 0)); // set listener orientation, 'dir'=forward direction (must be normalized), 'up'=up direction (must be normalized)
  52. ListenerClass& vel(C Vec &vel ); // set listener velocity
  53. #if !EE_PRIVATE
  54. private:
  55. #endif
  56. OrientP _orn;
  57. Vec _vel;
  58. Int _flag;
  59. ListenerClass();
  60. }extern
  61. Listener; // Main 3D Sound Listener Control
  62. /******************************************************************************/
  63. enum FADE_CURVE : Byte
  64. {
  65. FADE_LINEAR,
  66. FADE_SQRT ,
  67. FADE_EQUAL_POWER=FADE_SQRT,
  68. };
  69. #if EE_PRIVATE
  70. enum SOUND_FLAG
  71. {
  72. SOUND_CHANGED_POS =1<<0,
  73. SOUND_CHANGED_VEL =1<<1,
  74. SOUND_CHANGED_ORN =1<<2, // used for Listener
  75. SOUND_CHANGED_RANGE =1<<3,
  76. SOUND_CHANGED_VOLUME=1<<4,
  77. SOUND_CHANGED_SPEED =1<<5,
  78. SOUND_CHANGED_TIME =1<<6,
  79. SOUND_CHANGING_TIME =1<<7,
  80. SOUND_REMOVE =1<<8, // this can be set only if no 'Sound' references a '_Sound' anymore
  81. SOUND_NO_REF =1<<9, // if there's no external reference to this sound
  82. //SOUND_CHANGED_PAN =, this is not used
  83. //SOUND_CHANGED_PLAY =, this is not needed since it's always checked
  84. };
  85. const_mem_addr struct _Sound // can be moved however 'memAddressChanged' needs to be called afterwards
  86. {
  87. Bool _playing, _buffer_playing, _loop, _is3D, stream_loaded, deleted;
  88. Byte last_buffer, kill;
  89. VOLUME_GROUP volume_group;
  90. FADE_CURVE _fade_curve;
  91. Int flag;
  92. Long raw_pos;
  93. Flt _volume, _speed, _actual_speed, _range, _time, _fade, _fade_d, priority;
  94. Vec _pos, _vel;
  95. Str _name;
  96. SoundDataCallback *_callback;
  97. SoundStream _stream;
  98. SoundBuffer _buffer;
  99. SoundStream& stream();
  100. C SoundStream& stream()C {return ConstCast(T).stream();}
  101. void zero();
  102. void del ();
  103. void init(C Str &name, const_mem_addr SoundCallback *call, Bool is3D, VOLUME_GROUP volume_group);
  104. Bool init(C _Sound &src);
  105. // stop / play
  106. void stop ();
  107. void pause();
  108. void play ();
  109. // get / set
  110. Bool noRef ()C {return FlagTest(AtomicGet(flag), SOUND_NO_REF);} // if there's no external reference to this sound
  111. Bool is ()C; // if created
  112. Bool is3D ()C {return _is3D ;} // if is 3D
  113. Bool playing ()C {return _playing;} // if playing
  114. SOUND_CODEC codec ()C; // get source codec
  115. C Str& name ()C; // get source file name
  116. UID id ()C; // get source file name ID
  117. Long size ()C; // get source raw size in bytes
  118. Flt length ()C; // get source time length in seconds
  119. Long samples ()C; // get source number of samples
  120. Int channels ()C; // get source number of channels
  121. Int frequency()C; // get source frequency
  122. Int bitRate ()C; // get source bit rate
  123. Flt timeLeft ()C; // get sound remaining time , 0..length (), "length()-time()"
  124. void raw ( Long raw ); Long raw ()C; // set/get sound raw position, 0..size ()
  125. void sample( Long sample); Long sample ()C; // set/get sound sample position, 0..samples()
  126. void time ( Flt t ); Flt time ()C {return _time ;} // set/get sound time position, 0..length ()
  127. void frac ( Flt f ); Flt frac ()C; // set/get sound fraction position, 0..1
  128. void loop ( Bool loop ); Bool loop ()C {return _loop ;} // set/get sound looping , true/false
  129. void volume( Flt volume); Flt volume ()C {return _volume ;} // set/get sound volume , 0..1
  130. void speed ( Flt speed ); Flt speed ()C {return _speed ;} // set/get sound speed , 0..3, default=1
  131. void range ( Flt range ); Flt range ()C {return _range ;} // set/get sound 3D range , 0..Inf
  132. void pos (C Vec &pos ); C Vec& pos ()C {return _pos ;} // set/get sound 3D position
  133. void vel (C Vec &vel ); C Vec& vel ()C {return _vel ;} // set/get sound 3D velocity
  134. void preciseRaw (Long raw); Long preciseRaw ()C; // set/get sound raw position, 0..size ()
  135. void preciseTime(Flt t ); Flt preciseTime()C; // set/get sound time position, 0..length()
  136. void preciseFrac(Flt f ); Flt preciseFrac()C; // set/get sound fraction position, 0..1
  137. // operations
  138. Flt actualSpeed ()C;
  139. void setVolume ();
  140. void setSpeed ();
  141. Bool update (Flt dt);
  142. void updatePlaying(Int thread_index);
  143. void memAddressChanged();
  144. // fade
  145. Flt fade ()C {return _fade ;} // get current fade value
  146. void fadeCurve (FADE_CURVE curve ); FADE_CURVE fadeCurve()C {return _fade_curve;} // set/get fade curve
  147. void fadeInFromSilence(Flt fade_duration);
  148. void fadeIn (Flt fade_duration);
  149. void fadeOut (Flt fade_duration);
  150. // io
  151. Bool save (File &f, CChar *path=null)C; // 'path'=path at which resource is located (this is needed so that the sub-resources can be accessed with relative path), false on fail
  152. Int loadResult(File &f, CChar *path=null) ; // 'path'=path at which resource is located (this is needed so that the sub-resources can be accessed with relative path)
  153. // stream
  154. void setBuffer (Byte *buffer, Int size);
  155. Bool setBuffer (Bool buffer, Int thread_index);
  156. Bool setNextBuffer(Int thread_index) {return setBuffer(!last_buffer, thread_index);} // remember that 'last_buffer' can be 0xFF
  157. Bool testBuffer (Int thread_index);
  158. ~_Sound() {del();}
  159. _Sound() {stream_loaded=deleted=false; flag=0; zero();}
  160. NO_COPY_CONSTRUCTOR(_Sound);
  161. };
  162. #endif
  163. /******************************************************************************/
  164. struct Sound
  165. {
  166. // manage
  167. #if EE_PRIVATE
  168. Sound& _create(C Str &name, const_mem_addr SoundCallback *call, Bool is3D, VOLUME_GROUP volume_group);
  169. #endif
  170. Sound& del ();
  171. Sound& close (); // delete and wait until file handle is released, this method is slower than 'del', use it only if you need to modify the sound file
  172. Sound& create( C Str &name, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX); // create sound, 'name'=sound file name , , 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  173. Sound& create( C UID &id , Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX); // create sound, 'id' =sound file name ID, , 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  174. Sound& create(const_mem_addr SoundCallback &call, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX); // create sound, 'call'=sound call back , , 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  175. Sound& create( C Str &name, C Vec &pos, Flt range=1, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX); // create 3D sound, 'name'=sound file name , 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  176. Sound& create( C UID &id , C Vec &pos, Flt range=1, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX); // create 3D sound, 'id' =sound file name ID, 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  177. Sound& create(const_mem_addr SoundCallback &call, C Vec &pos, Flt range=1, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX); // create 3D sound, 'call'=sound call back , 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  178. Sound& play ( C Str &name, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX) {return create(name, loop, volume, volume_group).play();} // create and play sound, 'name'=sound file name , , 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  179. Sound& play ( C UID &id , Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX) {return create(id , loop, volume, volume_group).play();} // create and play sound, 'id' =sound file name ID, , 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  180. Sound& play (const_mem_addr SoundCallback &call, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX) {return create(call, loop, volume, volume_group).play();} // create and play sound, 'call'=sound call back , , 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  181. Sound& play ( C Str &name, C Vec &pos, Flt range=1, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX) {return create(name, pos, range, loop, volume, volume_group).play();} // create and play 3D sound, 'name'=sound file name , 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  182. Sound& play ( C UID &id , C Vec &pos, Flt range=1, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX) {return create(id , pos, range, loop, volume, volume_group).play();} // create and play 3D sound, 'id' =sound file name ID, 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  183. Sound& play (const_mem_addr SoundCallback &call, C Vec &pos, Flt range=1, Bool loop=false, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX) {return create(call, pos, range, loop, volume, volume_group).play();} // create and play 3D sound, 'call'=sound call back , 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'loop'=if sound is looped, 'volume'=sound volume (0..1)
  184. // stop / play
  185. Sound& stop (); // stop
  186. Sound& pause(); // pause
  187. Sound& play (); // play
  188. // get / set
  189. Bool is ()C; // if created
  190. Bool playing ()C; // if playing
  191. SOUND_CODEC codec ()C; // get source codec
  192. CChar8* codecName()C; // get source codec name
  193. C Str& name ()C; // get source file name
  194. UID id ()C; // get source file name ID
  195. Long size ()C; // get source raw size in bytes
  196. Flt length ()C; // get source time length in seconds
  197. Long samples ()C; // get source number of samples
  198. Int channels ()C; // get source number of channels
  199. Int frequency()C; // get source frequency
  200. Int bitRate ()C; // get source bit rate
  201. Flt timeLeft ()C; // get sound remaining time , 0..length (), "length()-time()"
  202. Sound& raw ( Long raw ); Long raw ()C; // set/get sound raw position , 0..size ()
  203. Sound& sample( Long sample); Long sample ()C; // set/get sound sample position , 0..samples()
  204. Sound& time ( Flt t ); Flt time ()C; // set/get sound time position , 0..length ()
  205. Sound& frac ( Flt f ); Flt frac ()C; // set/get sound fraction position , 0..1
  206. Sound& loop ( Bool loop ); Bool loop ()C; // set/get sound looping , true/false
  207. Sound& volume( Flt volume); Flt volume ()C; // set/get sound volume , 0..1
  208. Sound& speed ( Flt speed ); Flt speed ()C; // set/get sound speed , 0..3, default=1
  209. Sound& range ( Flt range ); Flt range ()C; // set/get sound 3D range multiplier, 0..Inf
  210. Sound& pos (C Vec &pos ); C Vec& pos ()C; // set/get sound 3D position
  211. Sound& vel (C Vec &vel ); C Vec& vel ()C; // set/get sound 3D velocity
  212. // volume fade
  213. Flt fade ()C; // get current fade value
  214. Sound& fadeCurve (FADE_CURVE curve ); FADE_CURVE fadeCurve()C; // set/get fade curve
  215. Sound& fadeInFromSilence(Flt fade_duration); // perform volume fade-in from silence to max volume
  216. Sound& fadeIn (Flt fade_duration); // perform volume fade-in from current volume level to max volume
  217. Sound& fadeOut (Flt fade_duration); // perform volume fade-out from current volume level to zero volume
  218. // data callback
  219. Sound& callback(SoundDataCallback *callback); SoundDataCallback* callback()C; // set/get data callback, it will be called every time a new portion of data is processed by the sound
  220. // io
  221. Bool save(File &f, CChar *path=null)C; // 'path'=path at which resource is located (this is needed so that the sub-resources can be accessed with relative path), false on fail
  222. Bool load(File &f, CChar *path=null) ; // 'path'=path at which resource is located (this is needed so that the sub-resources can be accessed with relative path), false on fail
  223. ~Sound() {del();}
  224. Sound() {sound=null;}
  225. Sound(C Sound &src);
  226. void operator=(C Sound &src);
  227. private:
  228. #if EE_PRIVATE
  229. _Sound *sound;
  230. #else
  231. Ptr sound;
  232. #endif
  233. };
  234. /******************************************************************************/
  235. Bool CacheSound(C Str &name); // cache sound file into memory so it won't be played every time from the disk, usage of this function is optional, you can call it at some initialization stage of your game, false on fail
  236. Bool CacheSound(C UID &id ); // cache sound file into memory so it won't be played every time from the disk, usage of this function is optional, you can call it at some initialization stage of your game, false on fail
  237. void SoundPlay( C Str &name, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX, Flt speed=1); // play sound, 'name'=sound file name , 'volume'=sound volume (0..1), 'speed'=sound speed (0..3)
  238. void SoundPlay( C UID &id , Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX, Flt speed=1); // play sound, 'id' =sound file name ID , 'volume'=sound volume (0..1), 'speed'=sound speed (0..3)
  239. void SoundPlay(const_mem_addr SoundCallback &call, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX, Flt speed=1); // play sound, 'call'=sound call back , 'volume'=sound volume (0..1), 'speed'=sound speed (0..3)
  240. void SoundPlay( C Str &name, C Vec &pos, Flt range=1, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX, Flt speed=1); // play 3D sound, 'name'=sound file name , 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'volume'=sound volume (0..1), 'speed'=sound speed (0..3)
  241. void SoundPlay( C UID &id , C Vec &pos, Flt range=1, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX, Flt speed=1); // play 3D sound, 'id' =sound file name ID, 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'volume'=sound volume (0..1), 'speed'=sound speed (0..3)
  242. void SoundPlay(const_mem_addr SoundCallback &call, C Vec &pos, Flt range=1, Flt volume=1, VOLUME_GROUP volume_group=VOLUME_FX, Flt speed=1); // play 3D sound, 'call'=sound call back , 'pos'=sound position in World, 'range'=sound range multiplier (0..Inf), 'volume'=sound volume (0..1), 'speed'=sound speed (0..3)
  243. Flt SoundMinVolume (); void SoundMinVolume (Flt volume); // get/set minimum volume required to play a sound , default=0.02, if volume of a sound is less than the specified value then it will be skipped for faster processing
  244. Int SoundMaxConcurrent(); void SoundMaxConcurrent(Int max ); // get/set maximum number of concurrent sounds , default=16 , if number of sounds exceeds the specified limit then sounds with lower priority will be skipped for faster processing, specifying negative value (-1) is the same as allowing unlimited number of concurrent sounds
  245. Int SoundMaxThreads (); void SoundMaxThreads (Int max ); // get/set maximum number of threads used for sound processing, default=1
  246. /******************************************************************************/
  247. #if EE_PRIVATE
  248. extern SyncLock SoundAPILock; // Sound API Lock
  249. extern Bool SoundAPI , // if Sound API is available
  250. SoundFunc ; // if we can access Sound functions
  251. void InitSound ();
  252. void ShutSound ();
  253. void InitSound2 ();
  254. void ShutSound2 ();
  255. void UpdateSound ();
  256. void PauseSound ();
  257. void ResumeSound ();
  258. void VolumeSound ();
  259. void EmulateSound3D();
  260. void SpeedSound ();
  261. Bool PlayingAnySound();
  262. #define MAX_SOUND_SPEED 2
  263. inline Flt SoundSpeed(Flt speed) {return Mid(speed, 0.0f, (Flt)MAX_SOUND_SPEED);}
  264. #if HAS_THREADS
  265. #define SOUND_TIMER 26 // 26 ms which is 38.5 Hz(fps), recommended value to be between 17ms(58.8Hz fps) .. 34ms(29.4Hz fps), also the callback will be triggered at least once per frame (due to 'SoundEvent' being triggered at the end of each frame to immediately process any changes), shorter timers result in smaller memory usage at the cost of additional overhead on the CPU
  266. #define SOUND_TIME (SOUND_TIMER*2*2*MAX_SOUND_SPEED) // 2 (2 half buffers) * 2 (safety due to sounds being started at different times) * MAX_SOUND_SPEED
  267. #define SOUND_TIME_RECORD (SOUND_TIMER*2*2) // 2 (2 half buffers) * 2 (safety due to sounds being started at different times), this doesn't need MAX_SOUND_SPEED because sounds are always recorded with speed=1
  268. #else
  269. #define SOUND_TIMER 50
  270. #define SOUND_TIME 1200 // when there are no threads available, set a big sound buffer, to allow some tolerance for pauses during loading
  271. #define SOUND_TIME_RECORD 500 // when there are no threads available, set a big sound buffer, to allow some tolerance for pauses during loading
  272. #endif
  273. #endif
  274. /******************************************************************************/