Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

OssMultiEngine.cpp 6.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. OssMultiEngine.cpp - Multi channel audio output for Open Sound System
  4. Copyright (C) 2014 Hans Petter Selasky
  5. This program is free software; you can redistribute it and/or
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 2
  8. of the License, or (at your option) any later version.
  9. */
  10. #include <cstring>
  11. #include <stdlib.h>
  12. #include <stdio.h>
  13. #include <fcntl.h>
  14. #include <errno.h>
  15. #include <sys/soundcard.h>
  16. #include <sys/stat.h>
  17. #include <sys/ioctl.h>
  18. #include <unistd.h>
  19. #include <iostream>
  20. #include <signal.h>
  21. #include "Nio.h"
  22. #include "../Misc/Master.h"
  23. #include "../Misc/Part.h"
  24. #include "../Misc/MiddleWare.h"
  25. #include "../Misc/Util.h"
  26. #include "OssMultiEngine.h"
  27. #include "Compressor.h"
  28. using namespace std;
  29. extern zyncarla::MiddleWare *middleware;
  30. namespace zyncarla {
  31. OssMultiEngine :: OssMultiEngine(const SYNTH_T &synth,
  32. const oss_devs_t &oss_devs)
  33. :AudioOut(synth),
  34. linux_oss_wave_out_dev(oss_devs.linux_wave_out)
  35. {
  36. /* setup variables */
  37. name = "OSS-MULTI";
  38. audioThread = 0;
  39. handle = -1;
  40. channels = 0;
  41. en = false;
  42. is32bit = false;
  43. buffersize = 0;
  44. /* compute worst case buffer size */
  45. maxbuffersize = NUM_MIDI_PARTS * sizeof(int) * synth.buffersize * 2;
  46. /* allocate buffer */
  47. smps.ps32 = new int[maxbuffersize / sizeof(int)];
  48. memset(smps.ps32, 0, maxbuffersize);
  49. /* setup compressor */
  50. unsigned peaksize = NUM_MIDI_PARTS * sizeof(float);
  51. peaks = new float[peaksize / sizeof(float)];
  52. memset(peaks, 0, peaksize);
  53. }
  54. OssMultiEngine :: ~OssMultiEngine()
  55. {
  56. Stop();
  57. delete [] smps.ps32;
  58. delete [] peaks;
  59. }
  60. bool
  61. OssMultiEngine :: openAudio()
  62. {
  63. int snd_samplerate;
  64. int snd_fragment;
  65. int x;
  66. /* check if already open */
  67. if (handle != -1)
  68. return (true);
  69. const char *device = getenv("DSP_DEVICE");
  70. if(device == 0)
  71. device = linux_oss_wave_out_dev;
  72. /* NOTE: PIPEs and FIFOs can block when opening them */
  73. handle = open(device, O_WRONLY, O_NONBLOCK);
  74. if (handle == -1) {
  75. cerr << "ERROR - I can't open the "
  76. << device << '.' << endl;
  77. return (false);
  78. }
  79. ioctl(handle, SNDCTL_DSP_RESET, 0);
  80. /* Figure out the correct format first */
  81. int snd_format16 = AFMT_S16_NE;
  82. #ifdef AFMT_S32_NE
  83. int snd_format32 = AFMT_S32_NE;
  84. if (ioctl(handle, SNDCTL_DSP_SETFMT, &snd_format32) == 0) {
  85. is32bit = true;
  86. } else
  87. #endif
  88. if (ioctl(handle, SNDCTL_DSP_SETFMT, &snd_format16) == 0) {
  89. is32bit = false;
  90. } else {
  91. cerr << "ERROR - Cannot set DSP format for "
  92. << device << '.' << endl;
  93. goto error;
  94. }
  95. for (x = NUM_MIDI_PARTS * 2; x >= 2; x -= 2) {
  96. if (ioctl(handle, SNDCTL_DSP_CHANNELS, &x) == 0)
  97. break;
  98. }
  99. if (x == 0) {
  100. cerr << "ERROR - Cannot set DSP channels for "
  101. << device << '.' << endl;
  102. goto error;
  103. }
  104. channels = x;
  105. snd_samplerate = synth.samplerate;
  106. ioctl(handle, SNDCTL_DSP_SPEED, &snd_samplerate);
  107. if (snd_samplerate != (int)synth.samplerate) {
  108. cerr << "ERROR - Cannot set samplerate for "
  109. << device << ". " << snd_samplerate
  110. << " != " << synth.samplerate << endl;
  111. goto error;
  112. }
  113. /* compute buffer size for 16-bit samples */
  114. buffersize = 2 * synth.buffersize * channels;
  115. if (is32bit)
  116. buffersize *= 2;
  117. for (x = 4; x < 20; x++) {
  118. if ((1 << x) >= buffersize)
  119. break;
  120. }
  121. snd_fragment = 0x20000 | x; /* 2x buffer */
  122. ioctl(handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment);
  123. pthread_attr_t attr;
  124. pthread_attr_init(&attr);
  125. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  126. pthread_create(&audioThread, &attr, _audioThreadCb, this);
  127. return (true);
  128. error:
  129. close(handle);
  130. handle = -1;
  131. return (false);
  132. }
  133. void
  134. OssMultiEngine :: stopAudio()
  135. {
  136. int fd = handle;
  137. /* check if already closed */
  138. if (fd == -1)
  139. return;
  140. handle = -1;
  141. /* close handle first, so that write() exits */
  142. close(fd);
  143. pthread_join(audioThread, 0);
  144. audioThread = 0;
  145. }
  146. bool
  147. OssMultiEngine :: Start()
  148. {
  149. return (openAudio());
  150. }
  151. void
  152. OssMultiEngine :: Stop()
  153. {
  154. stopAudio();
  155. }
  156. void
  157. OssMultiEngine :: setAudioEn(bool enable)
  158. {
  159. if (enable)
  160. openAudio();
  161. else
  162. stopAudio();
  163. }
  164. bool
  165. OssMultiEngine :: getAudioEn() const
  166. {
  167. return (handle != -1);
  168. }
  169. void *
  170. OssMultiEngine :: _audioThreadCb(void *arg)
  171. {
  172. return (static_cast<OssMultiEngine *>(arg))->audioThreadCb();
  173. }
  174. void *
  175. OssMultiEngine :: audioThreadCb()
  176. {
  177. /*
  178. * In case the audio device is a PIPE/FIFO, we need to ignore
  179. * any PIPE signals:
  180. */
  181. signal(SIGPIPE, SIG_IGN);
  182. set_realtime();
  183. while(getAudioEn()) {
  184. int error;
  185. int x;
  186. int y;
  187. /* get next buffer */
  188. getNext();
  189. /* extract audio from the "channels / 2" first parts */
  190. for (x = 0; x != channels; x += 2) {
  191. Part *part = middleware->spawnMaster()->part[x / 2];
  192. if (is32bit) {
  193. for (y = 0; y != synth.buffersize; y++) {
  194. float l = part->partoutl[y];
  195. float r = part->partoutr[y];
  196. stereoCompressor(synth.samplerate, peaks[x/2], l, r);
  197. smps.ps32[y * channels + x] = (int)(l * 2147483647.0f);
  198. smps.ps32[y * channels + x + 1] = (int)(r * 2147483647.0f);
  199. }
  200. } else {
  201. for (y = 0; y != synth.buffersize; y++) {
  202. float l = part->partoutl[y];
  203. float r = part->partoutr[y];
  204. stereoCompressor(synth.samplerate, peaks[x/2], l, r);
  205. smps.ps16[y * channels + x] = (short int)(l * 32767.0f);
  206. smps.ps16[y * channels + x + 1] = (short int)(r * 32767.0f);
  207. }
  208. }
  209. }
  210. /* write audio buffer to DSP device */
  211. do {
  212. /* make a copy of handle, in case of OSS audio disable */
  213. int fd = handle;
  214. if (fd == -1)
  215. goto done;
  216. error = write(fd, smps.ps32, buffersize);
  217. } while (error == -1 && errno == EINTR);
  218. if(error == -1)
  219. goto done;
  220. }
  221. done:
  222. pthread_exit(0);
  223. return (0);
  224. }
  225. }