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.

OssEngine.cpp 15KB

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