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.

286 lines
6.6KB

  1. /*
  2. ZynAddSubFX - a software synthesizer
  3. OSSaudiooutput.C - Audio output for Open Sound System
  4. Copyright (C) 2002-2005 Nasca Octavian Paul
  5. Author: Nasca Octavian Paul
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of version 2 of the GNU General Public License
  8. as published by the Free Software Foundation.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License (version 2 or later) for more details.
  13. You should have received a copy of the GNU General Public License (version 2)
  14. along with this program; if not, write to the Free Software Foundation,
  15. Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  16. */
  17. #include "OssEngine.h"
  18. #include "../Misc/Util.h"
  19. #include "../globals.h"
  20. #include <cstring>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <fcntl.h>
  24. #include <sys/soundcard.h>
  25. #include <sys/stat.h>
  26. #include <sys/ioctl.h>
  27. #include <unistd.h>
  28. #include <iostream>
  29. #include "InMgr.h"
  30. using namespace std;
  31. OssEngine::OssEngine()
  32. :AudioOut(), engThread(NULL)
  33. {
  34. name = "OSS";
  35. midi.handle = -1;
  36. audio.handle = -1;
  37. audio.smps = new short[synth->buffersize * 2];
  38. memset(audio.smps, 0, synth->bufferbytes);
  39. }
  40. OssEngine::~OssEngine()
  41. {
  42. Stop();
  43. delete [] audio.smps;
  44. }
  45. bool OssEngine::openAudio()
  46. {
  47. if(audio.handle != -1)
  48. return true; //already open
  49. int snd_bitsize = 16;
  50. int snd_fragment = 0x00080009; //fragment size (?);
  51. int snd_stereo = 1; //stereo;
  52. int snd_format = AFMT_S16_LE;
  53. int snd_samplerate = synth->samplerate;
  54. const char *device = config.cfg.LinuxOSSWaveOutDev;
  55. if(getenv("DSP_DEVICE"))
  56. device = getenv("DSP_DEVICE");
  57. audio.handle = open(device, O_WRONLY, 0);
  58. if(audio.handle == -1) {
  59. cerr << "ERROR - I can't open the "
  60. << device << '.' << endl;
  61. return false;
  62. }
  63. ioctl(audio.handle, SNDCTL_DSP_RESET, NULL);
  64. ioctl(audio.handle, SNDCTL_DSP_SETFMT, &snd_format);
  65. ioctl(audio.handle, SNDCTL_DSP_STEREO, &snd_stereo);
  66. ioctl(audio.handle, SNDCTL_DSP_SPEED, &snd_samplerate);
  67. ioctl(audio.handle, SNDCTL_DSP_SAMPLESIZE, &snd_bitsize);
  68. ioctl(audio.handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment);
  69. if(!getMidiEn()) {
  70. pthread_attr_t attr;
  71. pthread_attr_init(&attr);
  72. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  73. engThread = new pthread_t;
  74. pthread_create(engThread, &attr, _thread, this);
  75. }
  76. return true;
  77. }
  78. void OssEngine::stopAudio()
  79. {
  80. int handle = audio.handle;
  81. if(handle == -1) //already closed
  82. return;
  83. audio.handle = -1;
  84. if(!getMidiEn() && engThread)
  85. pthread_join(*engThread, NULL);
  86. delete engThread;
  87. engThread = NULL;
  88. close(handle);
  89. }
  90. bool OssEngine::Start()
  91. {
  92. bool good = true;
  93. if(!openAudio()) {
  94. cerr << "Failed to open OSS audio" << endl;
  95. good = false;
  96. }
  97. if(!openMidi()) {
  98. cerr << "Failed to open OSS midi" << endl;
  99. good = false;
  100. }
  101. return good;
  102. }
  103. void OssEngine::Stop()
  104. {
  105. stopAudio();
  106. stopMidi();
  107. }
  108. void OssEngine::setMidiEn(bool nval)
  109. {
  110. if(nval)
  111. openMidi();
  112. else
  113. stopMidi();
  114. }
  115. bool OssEngine::getMidiEn() const
  116. {
  117. return midi.handle != -1;
  118. }
  119. void OssEngine::setAudioEn(bool nval)
  120. {
  121. if(nval)
  122. openAudio();
  123. else
  124. stopAudio();
  125. }
  126. bool OssEngine::getAudioEn() const
  127. {
  128. return audio.handle != -1;
  129. }
  130. bool OssEngine::openMidi()
  131. {
  132. int handle = midi.handle;
  133. if(handle != -1)
  134. return true; //already open
  135. handle = open(config.cfg.LinuxOSSSeqInDev, O_RDONLY, 0);
  136. if(-1 == handle)
  137. return false;
  138. midi.handle = handle;
  139. if(!getAudioEn()) {
  140. pthread_attr_t attr;
  141. pthread_attr_init(&attr);
  142. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  143. engThread = new pthread_t;
  144. pthread_create(engThread, &attr, _thread, this);
  145. }
  146. return true;
  147. }
  148. void OssEngine::stopMidi()
  149. {
  150. int handle = midi.handle;
  151. if(handle == -1) //already closed
  152. return;
  153. midi.handle = -1;
  154. if(!getAudioEn() && engThread) {
  155. pthread_join(*engThread, NULL);
  156. delete engThread;
  157. engThread = NULL;
  158. }
  159. close(handle);
  160. }
  161. void *OssEngine::_thread(void *arg)
  162. {
  163. return (static_cast<OssEngine *>(arg))->thread();
  164. }
  165. void *OssEngine::thread()
  166. {
  167. unsigned char tmp[4] = {0, 0, 0, 0};
  168. set_realtime();
  169. while(getAudioEn() || getMidiEn()) {
  170. if(getAudioEn()) {
  171. const Stereo<float *> smps = getNext();
  172. float l, r;
  173. for(int i = 0; i < synth->buffersize; ++i) {
  174. l = smps.l[i];
  175. r = smps.r[i];
  176. if(l < -1.0f)
  177. l = -1.0f;
  178. else
  179. if(l > 1.0f)
  180. l = 1.0f;
  181. if(r < -1.0f)
  182. r = -1.0f;
  183. else
  184. if(r > 1.0f)
  185. r = 1.0f;
  186. audio.smps[i * 2] = (short int) (l * 32767.0f);
  187. audio.smps[i * 2 + 1] = (short int) (r * 32767.0f);
  188. }
  189. int handle = audio.handle;
  190. if(handle != -1)
  191. write(handle, audio.smps, synth->buffersize * 4); // *2 because is 16 bit, again * 2 because is stereo
  192. else
  193. break;
  194. }
  195. //Collect up to 30 midi events
  196. for(int k = 0; k < 30 && getMidiEn(); ++k) {
  197. static char escaped;
  198. memset(tmp, 0, 4);
  199. if(escaped) {
  200. tmp[0] = escaped;
  201. escaped = 0;
  202. }
  203. else {
  204. getMidi(tmp);
  205. if(!(tmp[0] & 0x80))
  206. continue;
  207. }
  208. getMidi(tmp + 1);
  209. if(tmp[1] & 0x80) {
  210. escaped = tmp[1];
  211. tmp[1] = 0;
  212. }
  213. else {
  214. getMidi(tmp + 2);
  215. if(tmp[2] & 0x80) {
  216. escaped = tmp[2];
  217. tmp[2] = 0;
  218. }
  219. else {
  220. getMidi(tmp + 3);
  221. if(tmp[3] & 0x80) {
  222. escaped = tmp[3];
  223. tmp[3] = 0;
  224. }
  225. }
  226. }
  227. midiProcess(tmp[0], tmp[1], tmp[2]);
  228. }
  229. }
  230. pthread_exit(NULL);
  231. return NULL;
  232. }
  233. void OssEngine::getMidi(unsigned char *midiPtr)
  234. {
  235. read(midi.handle, midiPtr, 1);
  236. }