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 7.0KB

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