Sound Extra.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /******************************************************************************
  2. Use 'AppVolume' to set the total application volume in the operating system.
  3. Use 'SoundRecord' to record sound data.
  4. /******************************************************************************/
  5. struct AppVolumeClass // Application Volume (in the system) Control
  6. {
  7. #if EE_PRIVATE
  8. void del ();
  9. Bool create();
  10. void muteEx(Bool mute); Bool muteEx()C; Bool muteFinal()C;
  11. #endif
  12. // get / set
  13. void volume(Flt volume); Flt volume(); // set/get volume (0..1)
  14. void mute (Bool mute ); Bool mute (); // set/get mute (true/false)
  15. #if !EE_PRIVATE
  16. private:
  17. #endif
  18. AppVolumeClass();
  19. }extern
  20. AppVolume;
  21. /******************************************************************************/
  22. const_mem_addr struct SoundRecord // !! must be stored in constant memory address !!
  23. {
  24. struct Device
  25. {
  26. Str name;
  27. Device() {_id.zero();}
  28. #if !EE_PRIVATE
  29. private:
  30. #endif
  31. UID _id;
  32. };
  33. static void GetDevices(MemPtr<Device> devices); // get list of sound record devices in the system
  34. // manage
  35. void del (); // manually delete
  36. Bool create(Device *device=null, Int bits=16, Int channels=1, Int frequency=44100); // start capturing using specified 'device' (use null for default), 'bits'=number of bits per sample (8 or 16), 'channels'=number of channels (1 or 2), 'frequency'=recording frequency, false on fail
  37. // get
  38. Bool is()C {return _handle!=null;} // if sound record is currently created
  39. // operations
  40. void update(); // update the sound record to get the most recent data, normally you don't need to call this as the buffer will get automatically updated over time, however you may want to call this if you need to make sure that all latest data was processed (if you want immediate access - lowest latency)
  41. // callbacks
  42. virtual void receivedData(CPtr data, Int size) {} // this method will be called upon receiving audio data, you should override this method to be able to process it, warning: this may get called on secondary thread
  43. #if EE_PRIVATE
  44. Int curPosNoLock()C;
  45. void updateNoLock();
  46. #endif
  47. ~SoundRecord() {del();}
  48. SoundRecord();
  49. #if !EE_PRIVATE
  50. private:
  51. #endif
  52. #if WINDOWS_OLD
  53. #if EE_PRIVATE
  54. #if DIRECT_SOUND
  55. IDirectSoundCapture8 *_handle;
  56. IDirectSoundCaptureBuffer *_dscb;
  57. #elif OPEN_AL
  58. ALCdevice *_handle;
  59. UIntPtr _block;
  60. #else
  61. Ptr _handle, _dscb;
  62. #endif
  63. #else
  64. Ptr _handle, _dscb;
  65. #endif
  66. Int _pos, _size;
  67. #elif WINDOWS_NEW
  68. #if EE_PRIVATE
  69. _SoundRecord *_handle;
  70. #else
  71. Ptr _handle;
  72. #endif
  73. #elif APPLE
  74. #if EE_PRIVATE
  75. AudioComponentInstance _handle; ASSERT(SIZE(AudioComponentInstance)==SIZE(Ptr));
  76. #else
  77. Ptr _handle;
  78. #endif
  79. UInt _flags;
  80. #elif ANDROID
  81. Ptr _handle;
  82. #else
  83. #if EE_PRIVATE
  84. #if OPEN_AL
  85. ALCdevice *_handle;
  86. Byte _block;
  87. #else
  88. Ptr _handle;
  89. Byte _block;
  90. #endif
  91. #else
  92. Ptr _handle;
  93. Byte _block;
  94. #endif
  95. #endif
  96. NO_COPY_CONSTRUCTOR(SoundRecord);
  97. };
  98. /******************************************************************************/
  99. #define OPUS_FREQUENCY 48000 // Opus Audio highest supported frequency 48kHz
  100. #define OPUS_BYTES 2 // Opus Audio is always stored using 2-byte samples
  101. #define OPUS_BITS 16 // Opus Audio is always stored using 16-bit samples
  102. #define OPUS_FRAME_SIZE_BEST_QUALITY 20 // Opus Audio frame size that provides the best quality, according to the documentation https://wiki.xiph.org/OpusFAQ#What_frame_size_should_I_use.3F - For file encoding, using a frame size larger than 20 ms will usually result in worse quality for the same bitrate because it constrains the encoder in the decisions it can make.
  103. /******************************************************************************/
  104. struct OpusEncoder
  105. {
  106. // manage
  107. Bool create(Int channels, Bool voice, Int frequency=OPUS_FREQUENCY); // create encoder, 'channels'=number of channels (1 or 2), 'voice'=if optimize encoder for Voice Over Internet (otherwise universal encoder is chosen, which is preferred for sounds and music), 'frequency'=only following values are supported: 48000, 24000, 16000, 12000, 8000 (if another value is provided, it will be rounded to the nearest supported value), false on fail
  108. // get / set
  109. Int frequency ()C; // get frequency
  110. Int bytes ()C {return OPUS_BYTES ;} // get bytes per sample
  111. Int bits ()C {return OPUS_BITS ;} // get bits per sample
  112. Int channels ()C {return _channels ;} // get number of channels
  113. Int block ()C {return bytes()*channels();} // get block size (bytes*channels)
  114. Int frameSamples()C {return _frame_samples ;} // get number of samples per frame
  115. Int frameLength ()C; OpusEncoder& frameLength(Int length ); // get/set frame length in milliseconds, smaller values result in worse quality but smaller latency(delay), higher values result in better quality but higher latency(delay) (2 .. 60 range supported), however Opus provides best quality for OPUS_FRAME_SIZE_BEST_QUALITY
  116. Int bitRate ()C; OpusEncoder& bitRate (Int bit_rate); // get/set encoding bit-rate in bits per second (500 .. 512,000 range supported)
  117. Bool vbr ()C; OpusEncoder& vbr (Bool on ); // get/set variable bit-rate (VBR), default=true
  118. Flt complexity ()C; OpusEncoder& complexity (Flt complex ); // get/set computational complexity (0..1, 0=fastest/low quality, 1=slowest/high quality)
  119. #if EE_PRIVATE
  120. void reset ();
  121. Int delay ()C;
  122. Bool flush(Int &flushed_samples, MemPtr<Byte> compressed_data, MemPtr<Int> packet_sizes); // flush any remaining buffered data, 'flushed_samples'=number of samples in the last packet that were originally set in 'encode' method, returns false on fail
  123. #endif
  124. // encode
  125. Bool encode(CPtr data, Int size, MemPtr<Byte> compressed_data, MemPtr<Int> packet_sizes); // feed the encoder with additional portion of data, 'data'=array of 16-bit samples (this should contain data for all channels specified in 'create' method, stereo should have per-channel data interleaved), 'size'=total raw length of 'data' in bytes, 'compressed_data'=this will contain compressed data of all packets in sequential order (data of first packet will be stored first, followed by second, third etc.), 'packet_sizes'=sizes of individual packets (in bytes), returns false on fail. For example if 'packet_sizes' has 2 elements, then 2 packets were created, 'packet_sizes[0]' specifies size of first packet, and 'packet_sizes[1]' specifies size of second packet, size of 'compressed_data' will be "packet_sizes[0]+packet_sizes[1]", it will contain data of first packet, followed by second packet. This method should be called continuously, once encoder gathers enough data it will generate compressed packets, in other cases when there's not yet enough data gathered, no packets will be generated.
  126. OpusEncoder& del();
  127. ~OpusEncoder() {del();}
  128. OpusEncoder();
  129. private:
  130. Ptr _encoder;
  131. Int _channels, _frame_samples, _last_sample_size;
  132. I16 _last_sample[2];
  133. Memc<Byte> _data;
  134. NO_COPY_CONSTRUCTOR(OpusEncoder);
  135. };
  136. /******************************************************************************/
  137. struct OpusDecoder
  138. {
  139. // manage
  140. Bool create(Int channels, Int frequency=OPUS_FREQUENCY); // create decoder, 'channels'=number of channels (1 or 2), 'frequency'=only following values are supported: 48000, 24000, 16000, 12000, 8000 (if another value is provided, it will be rounded to the nearest supported value), false on fail
  141. void reset(); // reset state, call when seeking or wanting to decode a different stream
  142. // get
  143. Int frequency()C; // get frequency
  144. Int bytes ()C {return OPUS_BYTES;} // get bytes per sample
  145. Int bits ()C {return OPUS_BITS ;} // get bits per sample
  146. Int channels ()C {return _channels ;} // get number of channels
  147. // decode
  148. Bool decode(CPtr packet_data, Int packet_size, MemPtr<Byte> decompressed_data ); // decode encoded 'packet_data' of 'packet_size' into 'decompressed_data', 'decompressed_data'=will hold decompressed data of 16-bit samples, returns false on fail
  149. Int decode(CPtr packet_data, Int packet_size, Ptr decompressed_data, Int decompressed_size); // decode encoded 'packet_data' of 'packet_size' into 'decompressed_data', 'decompressed_data'=will hold decompressed data of 16-bit samples, 'decompressed_size'=size of 'decompressed_data', returns actual size (in bytes) of decoded data, or -1 if error occurred
  150. OpusDecoder& del();
  151. ~OpusDecoder() {del();}
  152. OpusDecoder();
  153. private:
  154. Ptr _decoder;
  155. Int _channels;
  156. NO_COPY_CONSTRUCTOR(OpusDecoder);
  157. };
  158. /******************************************************************************/
  159. struct SndRawEncoder // Raw Encoder into Esenthel SND file format
  160. {
  161. Bool create(File &f, Int frequency, Int channels, Long samples=-1); // initialize the encoder, 'f'=file to write to (it must be already opened for writing), 'frequency'=sample rate per second, 'channels'=number of channels (1=mono, 2=stereo), 'samples'=number of samples in audio (if you don't know it yet, then set -1), returns false on fail
  162. Bool encode(CPtr data, Int size); // feed the encoder with additional portion of data, 'data'=array of 16-bit samples (this should contain data for all channels specified in 'create' method, stereo should have per-channel data interleaved), 'size'=total raw length of 'data' in bytes, returns false on fail
  163. Bool finish(); // you can optionally call this once after entire sound data has been passed to 'encode' calls to verify that last portion of data was compressed successfully, you don't need to call this as it is always called in 'del' method, returns false on fail
  164. SndRawEncoder& del();
  165. ~SndRawEncoder() {del();}
  166. SndRawEncoder();
  167. #if EE_PRIVATE
  168. void zero();
  169. #endif
  170. private:
  171. File *_f;
  172. Byte _block;
  173. Long _samples_pos;
  174. NO_COPY_CONSTRUCTOR(SndRawEncoder);
  175. };
  176. /******************************************************************************/
  177. struct WavEncoder // Raw Encoder into WAV file format
  178. {
  179. Bool create(File &f, Int bits, Int frequency, Int channels, Long samples=-1); // initialize the encoder, 'f'=file to write to (it must be already opened for writing), 'bits'=number of bits per sample (use 8 for 8-bit samples or 16 for 16-bit samples), 'frequency'=sample rate per second, 'channels'=number of channels (1=mono, 2=stereo), 'samples'=number of samples in audio (if you don't know it yet, then set -1), returns false on fail
  180. Bool encode(CPtr data, Int size); // feed the encoder with additional portion of data, 'data'=array of 16-bit samples (this should contain data for all channels specified in 'create' method, stereo should have per-channel data interleaved), 'size'=total raw length of 'data' in bytes, returns false on fail
  181. Bool finish(); // you can optionally call this once after entire sound data has been passed to 'encode' calls to verify that last portion of data was compressed successfully, you don't need to call this as it is always called in 'del' method, returns false on fail
  182. WavEncoder& del();
  183. ~WavEncoder() {del();}
  184. WavEncoder();
  185. #if EE_PRIVATE
  186. void zero();
  187. #endif
  188. private:
  189. File *_f;
  190. Long _size_pos;
  191. NO_COPY_CONSTRUCTOR(WavEncoder);
  192. };
  193. /******************************************************************************/
  194. #if EE_PRIVATE
  195. struct SndVorbisEncoder // Vorbis Encoder into Esenthel SND file format
  196. {
  197. Bool create(File &f, Long samples, Int frequency=44100, Int channels=2, Flt quality=0.2f); // initialize the encoder, 'f'=file to write to (it must be already opened for writing), 'samples'=number of samples in audio, 'frequency'=sample rate per second, 'channels'=number of channels (1=mono, 2=stereo), 'quality'=sound quality (-0.1 .. 1.0), for 44100Hz stereo, following quality results in Kbit/s bit rate: -0.1->45, 0.0->64, 0.1->80, 0.2->96, 0.3->112, 0.4->128, 0.5->160, 0.6->192, 0.7->224, 0.8->256, 0.9->320, 1.0->500, returns false on fail
  198. Bool encode(CPtr data, Int size); // feed the encoder with additional portion of data, 'data'=array of 16-bit samples (this should contain data for all channels specified in 'create' method, stereo should have per-channel data interleaved), 'size'=total raw length of 'data' in bytes, returns false on fail
  199. Bool finish(); // you can optionally call this once after entire sound data has been passed to 'encode' calls to verify that last portion of data was compressed successfully, you don't need to call this as it is always called in 'del' method, returns false on fail
  200. SndVorbisEncoder& del();
  201. ~SndVorbisEncoder() {del();}
  202. SndVorbisEncoder() {_encoder=null;}
  203. private:
  204. Ptr _encoder;
  205. NO_COPY_CONSTRUCTOR(SndVorbisEncoder);
  206. };
  207. #endif
  208. /******************************************************************************/
  209. struct OggVorbisEncoder // Vorbis Encoder into OGG file format
  210. {
  211. Bool create(File &f, Int frequency=44100, Int channels=2, Flt quality=0.2f); // initialize the encoder, 'f'=file to write to (it must be already opened for writing), 'frequency'=sample rate per second, 'channels'=number of channels (1=mono, 2=stereo), 'quality'=sound quality (-0.1 .. 1.0), for 44100Hz stereo, following quality results in Kbit/s bit rate: -0.1->45, 0.0->64, 0.1->80, 0.2->96, 0.3->112, 0.4->128, 0.5->160, 0.6->192, 0.7->224, 0.8->256, 0.9->320, 1.0->500, returns false on fail
  212. Bool encode(CPtr data, Int size); // feed the encoder with additional portion of data, 'data'=array of 16-bit samples (this should contain data for all channels specified in 'create' method, stereo should have per-channel data interleaved), 'size'=total raw length of 'data' in bytes, returns false on fail
  213. Bool finish(); // you can optionally call this once after entire sound data has been passed to 'encode' calls to verify that last portion of data was compressed successfully, you don't need to call this as it is always called in 'del' method, returns false on fail
  214. OggVorbisEncoder& del();
  215. ~OggVorbisEncoder() {del();}
  216. OggVorbisEncoder() {_encoder=null;}
  217. private:
  218. Ptr _encoder;
  219. NO_COPY_CONSTRUCTOR(OggVorbisEncoder);
  220. };
  221. /******************************************************************************/
  222. struct SndOpusEncoder // Opus Encoder into Esenthel SND file format
  223. {
  224. Bool create(File &f, Long samples, Int frequency, Int channels, Int bit_rate, Bool vbr=true); // initialize the encoder, 'f'=file to write to (it must be already opened for writing), 'samples'=number of samples in audio, 'frequency'=sample rate per second, 'channels'=number of channels (1=mono, 2=stereo), 'bit_rate'=encoding bit-rate in bits per second (500 .. 512,000 range supported), 'vbr'=variable bit-rate, returns false on fail
  225. Bool encode(CPtr data, Int size); // feed the encoder with additional portion of data, 'data'=array of 16-bit samples (this should contain data for all channels specified in 'create' method, stereo should have per-channel data interleaved), 'size'=total raw length of 'data' in bytes, returns false on fail
  226. Bool finish(); // you can optionally call this once after entire sound data has been passed to 'encode' calls to verify that last portion of data was compressed successfully, you don't need to call this as it is always called in 'del' method, returns false on fail
  227. Int frequency ()C; // get frequency
  228. Int bytes ()C; // get bytes per sample
  229. Int bits ()C; // get bits per sample
  230. Int channels ()C; // get number of channels
  231. Int block ()C; // get block size (bytes*channels)
  232. Int frameSamples()C; // get number of samples per frame
  233. Int bitRate ()C; SndOpusEncoder& bitRate(Int bit_rate); // get/set encoding bit-rate in bits per second (500 .. 512,000 range supported)
  234. SndOpusEncoder& del();
  235. ~SndOpusEncoder() {del();}
  236. SndOpusEncoder();
  237. #if EE_PRIVATE
  238. void zero();
  239. void write(Memt<Byte> &compressed_data, Memt<Int> &packet_sizes);
  240. #endif
  241. private:
  242. OpusEncoder _encoder;
  243. File *_f;
  244. Memc<U16> _packet_sizes;
  245. Long _packet_sizes_pos;
  246. UInt _packet_sizes_expected;
  247. Int _frequency;
  248. NO_COPY_CONSTRUCTOR(SndOpusEncoder);
  249. };
  250. /******************************************************************************/
  251. struct OggOpusEncoder // Opus Encoder into OGG file format
  252. {
  253. Bool create(File &f, Int channels, Int bit_rate, Bool vbr=true); // initialize the encoder, 'f'=file to write to (it must be already opened for writing), 'channels'=number of channels (1=mono, 2=stereo), 'bit_rate'=encoding bit-rate in bits per second (500 .. 512,000 range supported), 'vbr'=variable bit-rate, returns false on fail. There is no option to specify custom frequency, as Opus inside Ogg is always encoded at 48kHZ (therefore input to this class must be already in 48kHz)
  254. Bool encode(CPtr data, Int size); // feed the encoder with additional portion of data, 'data'=array of 16-bit samples (this should contain data for all channels specified in 'create' method, stereo should have per-channel data interleaved), 'size'=total raw length of 'data' in bytes, returns false on fail
  255. Bool finish(); // you can optionally call this once after entire sound data has been passed to 'encode' calls to verify that last portion of data was compressed successfully, you don't need to call this as it is always called in 'del' method, returns false on fail
  256. OggOpusEncoder& del();
  257. ~OggOpusEncoder() {del();}
  258. OggOpusEncoder() {_encoder=null;}
  259. private:
  260. Ptr _encoder;
  261. NO_COPY_CONSTRUCTOR(OggOpusEncoder);
  262. };
  263. /******************************************************************************/
  264. struct SoundDataCallback
  265. {
  266. virtual void data(Ptr data, Int size, C SoundStream &stream, Long raw_pos)=NULL;
  267. };
  268. struct Spectrometer : SoundDataCallback
  269. {
  270. Spectrometer& del ();
  271. Spectrometer& create(Int resolution);
  272. void get(Flt *meter, Int meter_elms, Flt time, FILTER_TYPE filter=FILTER_LINEAR); // set 'meter' of 'meter_elms' (recommended size is 'Spectrometer.resolution') to spectrometer reading at 'time' sound time, 'filter'=filtering (only FILTER_NONE, FILTER_LINEAR and FILTER_CUBIC are supported)
  273. // 'meter' array will have intensities for ranges from 1 Hz to SoundFrequency/2 Hz
  274. // which means that for 44100 Hz Sound, last 'meter' element will have 22050 Hz intensity
  275. // and for 48000 Hz Sound, last 'meter' element will have 24000 Hz intensity
  276. // and for 96000 Hz Sound, last 'meter' element will have 48000 Hz intensity
  277. Int resolution()C {return _image.w();} // get spectrometer resolution
  278. ~Spectrometer() {del();}
  279. Spectrometer();
  280. Spectrometer(Int resolution);
  281. virtual void data(Ptr data, Int size, C SoundStream &stream, Long raw_pos)override;
  282. private:
  283. Int _frequency;
  284. Flt _window_length;
  285. Ptr _fft;
  286. Image _image;
  287. Memc<Flt> _samples, _fft_out;
  288. #if EE_PRIVATE
  289. void free();
  290. void zero();
  291. #endif
  292. NO_COPY_CONSTRUCTOR(Spectrometer);
  293. };
  294. /******************************************************************************/
  295. #if EE_PRIVATE
  296. extern Memc<SoundRecord*> SoundRecords;
  297. #endif
  298. /******************************************************************************/