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.

277 lines
6.6KB

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