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.

282 lines
6.5KB

  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. audio.handle = open(config.cfg.LinuxOSSWaveOutDev, O_WRONLY, 0);
  55. if(audio.handle == -1) {
  56. cerr << "ERROR - I can't open the "
  57. << config.cfg.LinuxOSSWaveOutDev << '.' << endl;
  58. return false;
  59. }
  60. ioctl(audio.handle, SNDCTL_DSP_RESET, NULL);
  61. ioctl(audio.handle, SNDCTL_DSP_SETFMT, &snd_format);
  62. ioctl(audio.handle, SNDCTL_DSP_STEREO, &snd_stereo);
  63. ioctl(audio.handle, SNDCTL_DSP_SPEED, &snd_samplerate);
  64. ioctl(audio.handle, SNDCTL_DSP_SAMPLESIZE, &snd_bitsize);
  65. ioctl(audio.handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment);
  66. if(!getMidiEn()) {
  67. pthread_attr_t attr;
  68. pthread_attr_init(&attr);
  69. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  70. engThread = new pthread_t;
  71. pthread_create(engThread, &attr, _thread, this);
  72. }
  73. return true;
  74. }
  75. void OssEngine::stopAudio()
  76. {
  77. int handle = audio.handle;
  78. if(handle == -1) //already closed
  79. return;
  80. audio.handle = -1;
  81. if(!getMidiEn() && engThread)
  82. pthread_join(*engThread, NULL);
  83. delete engThread;
  84. engThread = NULL;
  85. close(handle);
  86. }
  87. bool OssEngine::Start()
  88. {
  89. bool good = true;
  90. if(!openAudio()) {
  91. cerr << "Failed to open OSS audio" << endl;
  92. good = false;
  93. }
  94. if(!openMidi()) {
  95. cerr << "Failed to open OSS midi" << endl;
  96. good = false;
  97. }
  98. return good;
  99. }
  100. void OssEngine::Stop()
  101. {
  102. stopAudio();
  103. stopMidi();
  104. }
  105. void OssEngine::setMidiEn(bool nval)
  106. {
  107. if(nval)
  108. openMidi();
  109. else
  110. stopMidi();
  111. }
  112. bool OssEngine::getMidiEn() const
  113. {
  114. return midi.handle != -1;
  115. }
  116. void OssEngine::setAudioEn(bool nval)
  117. {
  118. if(nval)
  119. openAudio();
  120. else
  121. stopAudio();
  122. }
  123. bool OssEngine::getAudioEn() const
  124. {
  125. return audio.handle != -1;
  126. }
  127. bool OssEngine::openMidi()
  128. {
  129. int handle = midi.handle;
  130. if(handle != -1)
  131. return true; //already open
  132. handle = open(config.cfg.LinuxOSSSeqInDev, O_RDONLY, 0);
  133. if(-1 == handle)
  134. return false;
  135. midi.handle = handle;
  136. if(!getAudioEn()) {
  137. pthread_attr_t attr;
  138. pthread_attr_init(&attr);
  139. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  140. engThread = new pthread_t;
  141. pthread_create(engThread, &attr, _thread, this);
  142. }
  143. return true;
  144. }
  145. void OssEngine::stopMidi()
  146. {
  147. int handle = midi.handle;
  148. if(handle == -1) //already closed
  149. return;
  150. midi.handle = -1;
  151. if(!getAudioEn() && engThread) {
  152. pthread_join(*engThread, NULL);
  153. delete engThread;
  154. engThread = NULL;
  155. }
  156. close(handle);
  157. }
  158. void *OssEngine::_thread(void *arg)
  159. {
  160. return (static_cast<OssEngine *>(arg))->thread();
  161. }
  162. void *OssEngine::thread()
  163. {
  164. unsigned char tmp[4] = {0, 0, 0, 0};
  165. set_realtime();
  166. while(getAudioEn() || getMidiEn()) {
  167. if(getAudioEn()) {
  168. const Stereo<float *> smps = getNext();
  169. float l, r;
  170. for(int i = 0; i < synth->buffersize; ++i) {
  171. l = smps.l[i];
  172. r = smps.r[i];
  173. if(l < -1.0f)
  174. l = -1.0f;
  175. else
  176. if(l > 1.0f)
  177. l = 1.0f;
  178. if(r < -1.0f)
  179. r = -1.0f;
  180. else
  181. if(r > 1.0f)
  182. r = 1.0f;
  183. audio.smps[i * 2] = (short int) (l * 32767.0f);
  184. audio.smps[i * 2 + 1] = (short int) (r * 32767.0f);
  185. }
  186. int handle = audio.handle;
  187. if(handle != -1)
  188. write(handle, audio.smps, synth->buffersize * 4); // *2 because is 16 bit, again * 2 because is stereo
  189. else
  190. break;
  191. }
  192. //Collect up to 30 midi events
  193. for(int k = 0; k < 30 && getMidiEn(); ++k) {
  194. static char escaped;
  195. memset(tmp, 0, 4);
  196. if(escaped) {
  197. tmp[0] = escaped;
  198. escaped = 0;
  199. }
  200. else {
  201. getMidi(tmp);
  202. if(!(tmp[0] & 0x80))
  203. continue;
  204. }
  205. getMidi(tmp + 1);
  206. if(tmp[1] & 0x80) {
  207. escaped = tmp[1];
  208. tmp[1] = 0;
  209. }
  210. else {
  211. getMidi(tmp + 2);
  212. if(tmp[2] & 0x80) {
  213. escaped = tmp[2];
  214. tmp[2] = 0;
  215. }
  216. else {
  217. getMidi(tmp + 3);
  218. if(tmp[3] & 0x80) {
  219. escaped = tmp[3];
  220. tmp[3] = 0;
  221. }
  222. }
  223. }
  224. midiProcess(tmp[0], tmp[1], tmp[2]);
  225. }
  226. }
  227. pthread_exit(NULL);
  228. return NULL;
  229. }
  230. void OssEngine::getMidi(unsigned char *midiPtr)
  231. {
  232. read(midi.handle, midiPtr, 1);
  233. }