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.

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