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.

474 lines
14KB

  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
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or (at your option) any later version.
  10. */
  11. #include "OssEngine.h"
  12. #include "Compressor.h"
  13. #include "../Misc/Util.h"
  14. #include "../Misc/Config.h"
  15. #include "../globals.h"
  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 "InMgr.h"
  28. using namespace std;
  29. /*
  30. * The following statemachine converts MIDI commands to USB MIDI
  31. * packets, derived from Linux's usbmidi.c, which was written by
  32. * "Clemens Ladisch". It is used to figure out when a MIDI command is
  33. * complete, without having to read the first byte of the next MIDI
  34. * command. This is useful when connecting to so-called system PIPEs
  35. * and FIFOs. See "man mkfifo".
  36. *
  37. * Return values:
  38. * 0: No command
  39. * Else: Command is complete
  40. */
  41. static unsigned char
  42. OssMidiParse(struct OssMidiParse &midi_parse,
  43. unsigned char cn, unsigned char b)
  44. {
  45. unsigned char p0 = (cn << 4);
  46. if(b >= 0xf8) {
  47. midi_parse.temp_0[0] = p0 | 0x0f;
  48. midi_parse.temp_0[1] = b;
  49. midi_parse.temp_0[2] = 0;
  50. midi_parse.temp_0[3] = 0;
  51. midi_parse.temp_cmd = midi_parse.temp_0;
  52. return (1);
  53. } else if(b >= 0xf0) {
  54. switch (b) {
  55. case 0xf0: /* system exclusive begin */
  56. midi_parse.temp_1[1] = b;
  57. midi_parse.state = OSSMIDI_ST_SYSEX_1;
  58. break;
  59. case 0xf1: /* MIDI time code */
  60. case 0xf3: /* song select */
  61. midi_parse.temp_1[1] = b;
  62. midi_parse.state = OSSMIDI_ST_1PARAM;
  63. break;
  64. case 0xf2: /* song position pointer */
  65. midi_parse.temp_1[1] = b;
  66. midi_parse.state = OSSMIDI_ST_2PARAM_1;
  67. break;
  68. case 0xf4: /* unknown */
  69. case 0xf5: /* unknown */
  70. midi_parse.state = OSSMIDI_ST_UNKNOWN;
  71. break;
  72. case 0xf6: /* tune request */
  73. midi_parse.temp_1[0] = p0 | 0x05;
  74. midi_parse.temp_1[1] = 0xf6;
  75. midi_parse.temp_1[2] = 0;
  76. midi_parse.temp_1[3] = 0;
  77. midi_parse.temp_cmd = midi_parse.temp_1;
  78. midi_parse.state = OSSMIDI_ST_UNKNOWN;
  79. return (1);
  80. case 0xf7: /* system exclusive end */
  81. switch (midi_parse.state) {
  82. case OSSMIDI_ST_SYSEX_0:
  83. midi_parse.temp_1[0] = p0 | 0x05;
  84. midi_parse.temp_1[1] = 0xf7;
  85. midi_parse.temp_1[2] = 0;
  86. midi_parse.temp_1[3] = 0;
  87. midi_parse.temp_cmd = midi_parse.temp_1;
  88. midi_parse.state = OSSMIDI_ST_UNKNOWN;
  89. return (1);
  90. case OSSMIDI_ST_SYSEX_1:
  91. midi_parse.temp_1[0] = p0 | 0x06;
  92. midi_parse.temp_1[2] = 0xf7;
  93. midi_parse.temp_1[3] = 0;
  94. midi_parse.temp_cmd = midi_parse.temp_1;
  95. midi_parse.state = OSSMIDI_ST_UNKNOWN;
  96. return (1);
  97. case OSSMIDI_ST_SYSEX_2:
  98. midi_parse.temp_1[0] = p0 | 0x07;
  99. midi_parse.temp_1[3] = 0xf7;
  100. midi_parse.temp_cmd = midi_parse.temp_1;
  101. midi_parse.state = OSSMIDI_ST_UNKNOWN;
  102. return (1);
  103. }
  104. midi_parse.state = OSSMIDI_ST_UNKNOWN;
  105. break;
  106. }
  107. } else if(b >= 0x80) {
  108. midi_parse.temp_1[1] = b;
  109. if((b >= 0xc0) && (b <= 0xdf)) {
  110. midi_parse.state = OSSMIDI_ST_1PARAM;
  111. } else {
  112. midi_parse.state = OSSMIDI_ST_2PARAM_1;
  113. }
  114. } else { /* b < 0x80 */
  115. switch (midi_parse.state) {
  116. case OSSMIDI_ST_1PARAM:
  117. if(midi_parse.temp_1[1] < 0xf0) {
  118. p0 |= midi_parse.temp_1[1] >> 4;
  119. } else {
  120. p0 |= 0x02;
  121. midi_parse.state = OSSMIDI_ST_UNKNOWN;
  122. }
  123. midi_parse.temp_1[0] = p0;
  124. midi_parse.temp_1[2] = b;
  125. midi_parse.temp_1[3] = 0;
  126. midi_parse.temp_cmd = midi_parse.temp_1;
  127. return (1);
  128. case OSSMIDI_ST_2PARAM_1:
  129. midi_parse.temp_1[2] = b;
  130. midi_parse.state = OSSMIDI_ST_2PARAM_2;
  131. break;
  132. case OSSMIDI_ST_2PARAM_2:
  133. if(midi_parse.temp_1[1] < 0xf0) {
  134. p0 |= midi_parse.temp_1[1] >> 4;
  135. midi_parse.state = OSSMIDI_ST_2PARAM_1;
  136. } else {
  137. p0 |= 0x03;
  138. midi_parse.state = OSSMIDI_ST_UNKNOWN;
  139. }
  140. midi_parse.temp_1[0] = p0;
  141. midi_parse.temp_1[3] = b;
  142. midi_parse.temp_cmd = midi_parse.temp_1;
  143. return (1);
  144. case OSSMIDI_ST_SYSEX_0:
  145. midi_parse.temp_1[1] = b;
  146. midi_parse.state = OSSMIDI_ST_SYSEX_1;
  147. break;
  148. case OSSMIDI_ST_SYSEX_1:
  149. midi_parse.temp_1[2] = b;
  150. midi_parse.state = OSSMIDI_ST_SYSEX_2;
  151. break;
  152. case OSSMIDI_ST_SYSEX_2:
  153. midi_parse.temp_1[0] = p0 | 0x04;
  154. midi_parse.temp_1[3] = b;
  155. midi_parse.temp_cmd = midi_parse.temp_1;
  156. midi_parse.state = OSSMIDI_ST_SYSEX_0;
  157. return (1);
  158. default:
  159. break;
  160. }
  161. }
  162. return (0);
  163. }
  164. OssEngine::OssEngine(const SYNTH_T &synth,
  165. const oss_devs_t& oss_devs)
  166. :AudioOut(synth), audioThread(NULL), midiThread(NULL),
  167. linux_oss_wave_out_dev(oss_devs.linux_wave_out),
  168. linux_oss_seq_in_dev(oss_devs.linux_seq_in)
  169. {
  170. name = "OSS";
  171. midi.handle = -1;
  172. audio.handle = -1;
  173. /* allocate worst case audio buffer */
  174. audio.smps.ps32 = new int[synth.buffersize * 2];
  175. memset(audio.smps.ps32, 0, sizeof(int) * synth.buffersize * 2);
  176. memset(&midi.state, 0, sizeof(midi.state));
  177. audio.peaks[0] = 0;
  178. }
  179. OssEngine::~OssEngine()
  180. {
  181. Stop();
  182. delete [] audio.smps.ps32;
  183. }
  184. bool OssEngine::openAudio()
  185. {
  186. int x;
  187. if(audio.handle != -1)
  188. return true; //already open
  189. int snd_fragment;
  190. int snd_stereo = 1; //stereo;
  191. int snd_samplerate = synth.samplerate;
  192. const char *device = getenv("DSP_DEVICE");
  193. if(device == NULL)
  194. device = linux_oss_wave_out_dev;
  195. /* NOTE: PIPEs and FIFOs can block when opening them */
  196. audio.handle = open(device, O_WRONLY, O_NONBLOCK);
  197. if(audio.handle == -1) {
  198. cerr << "ERROR - I can't open the "
  199. << device << '.' << endl;
  200. return false;
  201. }
  202. ioctl(audio.handle, SNDCTL_DSP_RESET, NULL);
  203. /* Figure out the correct format first */
  204. int snd_format16 = AFMT_S16_NE;
  205. #ifdef AFMT_S32_NE
  206. int snd_format32 = AFMT_S32_NE;
  207. if (ioctl(audio.handle, SNDCTL_DSP_SETFMT, &snd_format32) == 0) {
  208. audio.is32bit = true;
  209. } else
  210. #endif
  211. if (ioctl(audio.handle, SNDCTL_DSP_SETFMT, &snd_format16) == 0) {
  212. audio.is32bit = false;
  213. } else {
  214. cerr << "ERROR - I cannot set DSP format for "
  215. << device << '.' << endl;
  216. goto error;
  217. }
  218. ioctl(audio.handle, SNDCTL_DSP_STEREO, &snd_stereo);
  219. ioctl(audio.handle, SNDCTL_DSP_SPEED, &snd_samplerate);
  220. if (snd_samplerate != (int)synth.samplerate) {
  221. cerr << "ERROR - Cannot set samplerate for "
  222. << device << ". " << snd_samplerate
  223. << " != " << synth.samplerate << endl;
  224. goto error;
  225. }
  226. /* compute buffer size for 16-bit stereo samples */
  227. audio.buffersize = 4 * synth.buffersize;
  228. if (audio.is32bit)
  229. audio.buffersize *= 2;
  230. for (x = 4; x < 20; x++) {
  231. if ((1 << x) >= audio.buffersize)
  232. break;
  233. }
  234. snd_fragment = 0x20000 | x; /* 2x buffer */
  235. ioctl(audio.handle, SNDCTL_DSP_SETFRAGMENT, &snd_fragment);
  236. pthread_attr_t attr;
  237. pthread_attr_init(&attr);
  238. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  239. audioThread = new pthread_t;
  240. pthread_create(audioThread, &attr, _audioThreadCb, this);
  241. return true;
  242. error:
  243. close(audio.handle);
  244. audio.handle = -1;
  245. return false;
  246. }
  247. void OssEngine::stopAudio()
  248. {
  249. int handle = audio.handle;
  250. if(handle == -1) //already closed
  251. return;
  252. audio.handle = -1;
  253. /* close handle first, so that write() exits */
  254. close(handle);
  255. pthread_join(*audioThread, NULL);
  256. delete audioThread;
  257. audioThread = NULL;
  258. }
  259. bool OssEngine::Start()
  260. {
  261. bool good = true;
  262. if(!openAudio()) {
  263. cerr << "Failed to open OSS audio" << endl;
  264. good = false;
  265. }
  266. if(!openMidi()) {
  267. cerr << "Failed to open OSS midi" << endl;
  268. good = false;
  269. }
  270. return good;
  271. }
  272. void OssEngine::Stop()
  273. {
  274. stopAudio();
  275. stopMidi();
  276. }
  277. void OssEngine::setMidiEn(bool nval)
  278. {
  279. if(nval)
  280. openMidi();
  281. else
  282. stopMidi();
  283. }
  284. bool OssEngine::getMidiEn() const
  285. {
  286. return midi.handle != -1;
  287. }
  288. void OssEngine::setAudioEn(bool nval)
  289. {
  290. if(nval)
  291. openAudio();
  292. else
  293. stopAudio();
  294. }
  295. bool OssEngine::getAudioEn() const
  296. {
  297. return audio.handle != -1;
  298. }
  299. bool OssEngine::openMidi()
  300. {
  301. int handle = midi.handle;
  302. if(handle != -1)
  303. return true; //already open
  304. const char *device = getenv("MIDI_DEVICE");
  305. if(device == NULL)
  306. device = linux_oss_seq_in_dev;
  307. /* NOTE: PIPEs and FIFOs can block when opening them */
  308. handle = open(device, O_RDONLY, O_NONBLOCK);
  309. if(-1 == handle)
  310. return false;
  311. midi.handle = handle;
  312. pthread_attr_t attr;
  313. pthread_attr_init(&attr);
  314. pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
  315. midiThread = new pthread_t;
  316. pthread_create(midiThread, &attr, _midiThreadCb, this);
  317. return true;
  318. }
  319. void OssEngine::stopMidi()
  320. {
  321. int handle = midi.handle;
  322. if(handle == -1) //already closed
  323. return;
  324. midi.handle = -1;
  325. /* close handle first, so that read() exits */
  326. close(handle);
  327. pthread_join(*midiThread, NULL);
  328. delete midiThread;
  329. midiThread = NULL;
  330. }
  331. void *OssEngine::_audioThreadCb(void *arg)
  332. {
  333. return (static_cast<OssEngine *>(arg))->audioThreadCb();
  334. }
  335. void *OssEngine::_midiThreadCb(void *arg)
  336. {
  337. return (static_cast<OssEngine *>(arg))->midiThreadCb();
  338. }
  339. void *OssEngine::audioThreadCb()
  340. {
  341. /*
  342. * In case the audio device is a PIPE/FIFO,
  343. * we need to ignore any PIPE signals:
  344. */
  345. signal(SIGPIPE, SIG_IGN);
  346. set_realtime();
  347. while(getAudioEn()) {
  348. const Stereo<float *> smps = getNext();
  349. for(int i = 0; i < synth.buffersize; ++i) {
  350. float l = smps.l[i];
  351. float r = smps.r[i];
  352. stereoCompressor(synth.samplerate, audio.peaks[0], l, r);
  353. if (audio.is32bit) {
  354. audio.smps.ps32[i * 2] = (int) (l * 2147483647.0f);
  355. audio.smps.ps32[i * 2 + 1] = (int) (r * 2147483647.0f);
  356. } else {/* 16bit */
  357. audio.smps.ps16[i * 2] = (short int) (l * 32767.0f);
  358. audio.smps.ps16[i * 2 + 1] = (short int) (r * 32767.0f);
  359. }
  360. }
  361. int error;
  362. do {
  363. /* make a copy of handle, in case of OSS audio disable */
  364. int handle = audio.handle;
  365. if(handle == -1)
  366. goto done;
  367. error = write(handle, audio.smps.ps32, audio.buffersize);
  368. } while (error == -1 && errno == EINTR);
  369. if(error == -1)
  370. goto done;
  371. }
  372. done:
  373. pthread_exit(NULL);
  374. return NULL;
  375. }
  376. void *OssEngine::midiThreadCb()
  377. {
  378. /*
  379. * In case the MIDI device is a PIPE/FIFO,
  380. * we need to ignore any PIPE signals:
  381. */
  382. signal(SIGPIPE, SIG_IGN);
  383. set_realtime();
  384. while(getMidiEn()) {
  385. unsigned char tmp;
  386. int error;
  387. do {
  388. /* make a copy of handle, in case of OSS MIDI disable */
  389. int handle = midi.handle;
  390. if(handle == -1)
  391. goto done;
  392. error = read(handle, &tmp, 1);
  393. } while (error == -1 && errno == EINTR);
  394. /* check that we got one byte */
  395. if(error != 1)
  396. goto done;
  397. /* feed MIDI byte into statemachine */
  398. if(OssMidiParse(midi.state, 0, tmp)) {
  399. /* we got a complete MIDI command */
  400. midiProcess(midi.state.temp_cmd[1],
  401. midi.state.temp_cmd[2],
  402. midi.state.temp_cmd[3]);
  403. }
  404. }
  405. done:
  406. pthread_exit(NULL);
  407. return NULL;
  408. }