jack2 codebase
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.

517 lines
20KB

  1. /*
  2. Copyright (C) 2008 Grame
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2 of the License, or
  6. (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  14. */
  15. #ifndef __JackAlsaIOAdapter__
  16. #define __JackAlsaIOAdapter__
  17. #include <math.h>
  18. #include <limits.h>
  19. #include <alsa/asoundlib.h>
  20. #include "JackIOAdapter.h"
  21. #include "JackPlatformThread.h"
  22. #include "jack.h"
  23. namespace Jack
  24. {
  25. inline void* aligned_calloc(size_t nmemb, size_t size) { return (void*)((size_t)(calloc((nmemb*size) + 15, sizeof(char))) + 15 & ~15); }
  26. #define max(x,y) (((x)>(y)) ? (x) : (y))
  27. #define min(x,y) (((x)<(y)) ? (x) : (y))
  28. #define check_error(err) if (err) { printf("%s:%d, alsa error %d : %s\n", __FILE__, __LINE__, err, snd_strerror(err)); return err; }
  29. #define check_error_msg(err,msg) if (err) { fprintf(stderr, "%s:%d, %s : %s(%d)\n", __FILE__, __LINE__, msg, snd_strerror(err), err); return err; }
  30. #define display_error_msg(err,msg) if (err) { fprintf(stderr, "%s:%d, %s : %s(%d)\n", __FILE__, __LINE__, msg, snd_strerror(err), err); }
  31. /**
  32. * A convenient class to pass parameters to AudioInterface
  33. */
  34. class AudioParam
  35. {
  36. public:
  37. const char* fCardName;
  38. unsigned int fFrequency;
  39. int fBuffering;
  40. unsigned int fSoftInputs;
  41. unsigned int fSoftOutputs;
  42. public:
  43. AudioParam() :
  44. fCardName("hw:0"),
  45. fFrequency(44100),
  46. fBuffering(512),
  47. fSoftInputs(2),
  48. fSoftOutputs(2)
  49. {}
  50. AudioParam(int input, int output, jack_nframes_t buffer_size, jack_nframes_t sample_rate) :
  51. fCardName("hw:0"),
  52. fFrequency(sample_rate),
  53. fBuffering(buffer_size),
  54. fSoftInputs(input),
  55. fSoftOutputs(output)
  56. {}
  57. AudioParam& cardName(const char* n) { fCardName = n; return *this; }
  58. AudioParam& frequency(int f) { fFrequency = f; return *this; }
  59. AudioParam& buffering(int fpb) { fBuffering = fpb; return *this; }
  60. AudioParam& inputs(int n) { fSoftInputs = n; return *this; }
  61. AudioParam& outputs(int n) { fSoftOutputs = n; return *this; }
  62. };
  63. /**
  64. * An ALSA audio interface
  65. */
  66. class AudioInterface : public AudioParam
  67. {
  68. public:
  69. snd_pcm_t* fOutputDevice;
  70. snd_pcm_t* fInputDevice;
  71. snd_pcm_hw_params_t* fInputParams;
  72. snd_pcm_hw_params_t* fOutputParams;
  73. snd_pcm_format_t fSampleFormat;
  74. snd_pcm_access_t fSampleAccess;
  75. unsigned int fCardInputs;
  76. unsigned int fCardOutputs;
  77. unsigned int fChanInputs;
  78. unsigned int fChanOutputs;
  79. // interleaved mode audiocard buffers
  80. void* fInputCardBuffer;
  81. void* fOutputCardBuffer;
  82. // non interleaved mode audiocard buffers
  83. void* fInputCardChannels[256];
  84. void* fOutputCardChannels[256];
  85. // non interleaved mod, floating point software buffers
  86. float* fInputSoftChannels[256];
  87. float* fOutputSoftChannels[256];
  88. public:
  89. const char* cardName() { return fCardName; }
  90. int frequency() { return fFrequency; }
  91. int buffering() { return fBuffering; }
  92. float** inputSoftChannels() { return fInputSoftChannels; }
  93. float** outputSoftChannels() { return fOutputSoftChannels; }
  94. AudioInterface(const AudioParam& ap = AudioParam()) : AudioParam(ap)
  95. {
  96. fInputDevice = 0;
  97. fOutputDevice = 0;
  98. fInputParams = 0;
  99. fOutputParams = 0;
  100. }
  101. /**
  102. * Open the audio interface
  103. */
  104. int open()
  105. {
  106. int err;
  107. // allocation d'un stream d'entree et d'un stream de sortie
  108. err = snd_pcm_open(&fInputDevice, fCardName, SND_PCM_STREAM_CAPTURE, 0); check_error(err)
  109. err = snd_pcm_open(&fOutputDevice, fCardName, SND_PCM_STREAM_PLAYBACK, 0); check_error(err)
  110. // recherche des parametres d'entree
  111. err = snd_pcm_hw_params_malloc(&fInputParams); check_error(err);
  112. setAudioParams(fInputDevice, fInputParams);
  113. snd_pcm_hw_params_get_channels(fInputParams, &fCardInputs);
  114. // recherche des parametres de sortie
  115. err = snd_pcm_hw_params_malloc( &fOutputParams ); check_error(err)
  116. setAudioParams(fOutputDevice, fOutputParams);
  117. snd_pcm_hw_params_get_channels(fOutputParams, &fCardOutputs);
  118. printf("inputs : %ud, outputs : %ud\n", fCardInputs, fCardOutputs);
  119. // enregistrement des parametres d'entree-sortie
  120. err = snd_pcm_hw_params(fInputDevice, fInputParams); check_error (err);
  121. err = snd_pcm_hw_params(fOutputDevice, fOutputParams); check_error (err);
  122. //assert(snd_pcm_hw_params_get_period_size(fInputParams,NULL) == snd_pcm_hw_params_get_period_size(fOutputParams,NULL));
  123. // allocation of alsa buffers
  124. if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {
  125. fInputCardBuffer = aligned_calloc(interleavedBufferSize(fInputParams), 1);
  126. fOutputCardBuffer = aligned_calloc(interleavedBufferSize(fOutputParams), 1);
  127. } else {
  128. for (unsigned int i = 0; i < fCardInputs; i++) {
  129. fInputCardChannels[i] = aligned_calloc(noninterleavedBufferSize(fInputParams), 1);
  130. }
  131. for (unsigned int i = 0; i < fCardOutputs; i++) {
  132. fOutputCardChannels[i] = aligned_calloc(noninterleavedBufferSize(fOutputParams), 1);
  133. }
  134. }
  135. // allocation of floating point buffers needed by the dsp code
  136. fChanInputs = max(fSoftInputs, fCardInputs); assert (fChanInputs < 256);
  137. fChanOutputs = max(fSoftOutputs, fCardOutputs); assert (fChanOutputs < 256);
  138. for (unsigned int i = 0; i < fChanInputs; i++) {
  139. fInputSoftChannels[i] = (float*) aligned_calloc (fBuffering, sizeof(float));
  140. for (int j = 0; j < fBuffering; j++) {
  141. fInputSoftChannels[i][j] = 0.0;
  142. }
  143. }
  144. for (unsigned int i = 0; i < fChanOutputs; i++) {
  145. fOutputSoftChannels[i] = (float*) aligned_calloc (fBuffering, sizeof(float));
  146. for (int j = 0; j < fBuffering; j++) {
  147. fOutputSoftChannels[i][j] = 0.0;
  148. }
  149. }
  150. return 0;
  151. }
  152. int setAudioParams(snd_pcm_t* stream, snd_pcm_hw_params_t* params)
  153. {
  154. int err;
  155. // set params record with initial values
  156. err = snd_pcm_hw_params_any ( stream, params );
  157. check_error_msg(err, "unable to init parameters")
  158. // set alsa access mode (and fSampleAccess field) either to non interleaved or interleaved
  159. err = snd_pcm_hw_params_set_access (stream, params, SND_PCM_ACCESS_RW_NONINTERLEAVED );
  160. if (err) {
  161. err = snd_pcm_hw_params_set_access (stream, params, SND_PCM_ACCESS_RW_INTERLEAVED );
  162. check_error_msg(err, "unable to set access mode neither to non-interleaved or to interleaved");
  163. }
  164. snd_pcm_hw_params_get_access(params, &fSampleAccess);
  165. // search for 32-bits or 16-bits format
  166. err = snd_pcm_hw_params_set_format (stream, params, SND_PCM_FORMAT_S32);
  167. if (err) {
  168. err = snd_pcm_hw_params_set_format (stream, params, SND_PCM_FORMAT_S16);
  169. check_error_msg(err, "unable to set format to either 32-bits or 16-bits");
  170. }
  171. snd_pcm_hw_params_get_format(params, &fSampleFormat);
  172. // set sample frequency
  173. snd_pcm_hw_params_set_rate_near (stream, params, &fFrequency, 0);
  174. // set period and period size (buffering)
  175. err = snd_pcm_hw_params_set_period_size (stream, params, fBuffering, 0);
  176. check_error_msg(err, "period size not available");
  177. err = snd_pcm_hw_params_set_periods (stream, params, 2, 0);
  178. check_error_msg(err, "number of periods not available");
  179. return 0;
  180. }
  181. ssize_t interleavedBufferSize(snd_pcm_hw_params_t* params)
  182. {
  183. _snd_pcm_format format; snd_pcm_hw_params_get_format(params, &format);
  184. snd_pcm_uframes_t psize; snd_pcm_hw_params_get_period_size(params, &psize, NULL);
  185. unsigned int channels; snd_pcm_hw_params_get_channels(params, &channels);
  186. ssize_t bsize = snd_pcm_format_size (format, psize * channels);
  187. return bsize;
  188. }
  189. ssize_t noninterleavedBufferSize(snd_pcm_hw_params_t* params)
  190. {
  191. _snd_pcm_format format; snd_pcm_hw_params_get_format(params, &format);
  192. snd_pcm_uframes_t psize; snd_pcm_hw_params_get_period_size(params, &psize, NULL);
  193. ssize_t bsize = snd_pcm_format_size (format, psize);
  194. return bsize;
  195. }
  196. int close()
  197. {
  198. // TODO
  199. return 0;
  200. }
  201. /**
  202. * Read audio samples from the audio card. Convert samples to floats and take
  203. * care of interleaved buffers
  204. */
  205. int read()
  206. {
  207. if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {
  208. int count = snd_pcm_readi(fInputDevice, fInputCardBuffer, fBuffering);
  209. if (count<0) {
  210. display_error_msg(count, "reading samples");
  211. int err = snd_pcm_prepare(fInputDevice);
  212. check_error_msg(err, "preparing input stream");
  213. }
  214. if (fSampleFormat == SND_PCM_FORMAT_S16) {
  215. short* buffer16b = (short*) fInputCardBuffer;
  216. for (int s = 0; s < fBuffering; s++) {
  217. for (unsigned int c = 0; c < fCardInputs; c++) {
  218. fInputSoftChannels[c][s] = float(buffer16b[c + s*fCardInputs])*(1.0/float(SHRT_MAX));
  219. }
  220. }
  221. } else { // SND_PCM_FORMAT_S32
  222. long* buffer32b = (long*) fInputCardBuffer;
  223. for (int s = 0; s < fBuffering; s++) {
  224. for (unsigned int c = 0; c < fCardInputs; c++) {
  225. fInputSoftChannels[c][s] = float(buffer32b[c + s*fCardInputs])*(1.0/float(LONG_MAX));
  226. }
  227. }
  228. }
  229. } else if (fSampleAccess == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
  230. int count = snd_pcm_readn(fInputDevice, fInputCardChannels, fBuffering);
  231. if (count<0) {
  232. display_error_msg(count, "reading samples");
  233. int err = snd_pcm_prepare(fInputDevice);
  234. check_error_msg(err, "preparing input stream");
  235. }
  236. if (fSampleFormat == SND_PCM_FORMAT_S16) {
  237. for (unsigned int c = 0; c < fCardInputs; c++) {
  238. short* chan16b = (short*) fInputCardChannels[c];
  239. for (int s = 0; s < fBuffering; s++) {
  240. fInputSoftChannels[c][s] = float(chan16b[s])*(1.0/float(SHRT_MAX));
  241. }
  242. }
  243. } else { // SND_PCM_FORMAT_S32
  244. for (unsigned int c = 0; c < fCardInputs; c++) {
  245. long* chan32b = (long*) fInputCardChannels[c];
  246. for (int s = 0; s < fBuffering; s++) {
  247. fInputSoftChannels[c][s] = float(chan32b[s])*(1.0/float(LONG_MAX));
  248. }
  249. }
  250. }
  251. } else {
  252. check_error_msg(-10000, "unknow access mode");
  253. }
  254. return 0;
  255. }
  256. /**
  257. * write the output soft channels to the audio card. Convert sample
  258. * format and interleaves buffers when needed
  259. */
  260. int write()
  261. {
  262. recovery:
  263. if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) {
  264. if (fSampleFormat == SND_PCM_FORMAT_S16) {
  265. short* buffer16b = (short*) fOutputCardBuffer;
  266. for (int f = 0; f < fBuffering; f++) {
  267. for (unsigned int c = 0; c < fCardOutputs; c++) {
  268. float x = fOutputSoftChannels[c][f];
  269. buffer16b[c + f * fCardOutputs] = short(max(min(x, 1.0), -1.0) * float(SHRT_MAX));
  270. }
  271. }
  272. } else { // SND_PCM_FORMAT_S32
  273. long* buffer32b = (long*) fOutputCardBuffer;
  274. for (int f = 0; f < fBuffering; f++) {
  275. for (unsigned int c = 0; c < fCardOutputs; c++) {
  276. float x = fOutputSoftChannels[c][f];
  277. buffer32b[c + f * fCardOutputs] = long( max(min(x, 1.0), -1.0) * float(LONG_MAX));
  278. }
  279. }
  280. }
  281. int count = snd_pcm_writei(fOutputDevice, fOutputCardBuffer, fBuffering);
  282. if (count<0) {
  283. display_error_msg(count, "w3");
  284. int err = snd_pcm_prepare(fOutputDevice);
  285. check_error_msg(err, "preparing output stream");
  286. goto recovery;
  287. }
  288. } else if (fSampleAccess == SND_PCM_ACCESS_RW_NONINTERLEAVED) {
  289. if (fSampleFormat == SND_PCM_FORMAT_S16) {
  290. for (unsigned int c = 0; c < fCardOutputs; c++) {
  291. short* chan16b = (short*) fOutputCardChannels[c];
  292. for (int f = 0; f < fBuffering; f++) {
  293. float x = fOutputSoftChannels[c][f];
  294. chan16b[f] = short(max(min(x,1.0), -1.0) * float(SHRT_MAX)) ;
  295. }
  296. }
  297. } else { // SND_PCM_FORMAT_S32
  298. for (unsigned int c = 0; c < fCardOutputs; c++) {
  299. long* chan32b = (long*) fOutputCardChannels[c];
  300. for (int f = 0; f < fBuffering; f++) {
  301. float x = fOutputSoftChannels[c][f];
  302. chan32b[f] = long(max(min(x,1.0),-1.0) * float(LONG_MAX)) ;
  303. }
  304. }
  305. }
  306. int count = snd_pcm_writen(fOutputDevice, fOutputCardChannels, fBuffering);
  307. if (count<0) {
  308. display_error_msg(count, "w3");
  309. int err = snd_pcm_prepare(fOutputDevice);
  310. check_error_msg(err, "preparing output stream");
  311. goto recovery;
  312. }
  313. } else {
  314. check_error_msg(-10000, "unknow access mode");
  315. }
  316. return 0;
  317. }
  318. /**
  319. * print short information on the audio device
  320. */
  321. int shortinfo()
  322. {
  323. int err;
  324. snd_ctl_card_info_t* card_info;
  325. snd_ctl_t* ctl_handle;
  326. err = snd_ctl_open(&ctl_handle, fCardName, 0); check_error(err);
  327. snd_ctl_card_info_alloca(&card_info);
  328. err = snd_ctl_card_info(ctl_handle, card_info); check_error(err);
  329. printf("%s|%d|%d|%d|%d|%s\n",
  330. snd_ctl_card_info_get_driver(card_info),
  331. fCardInputs, fCardOutputs,
  332. fFrequency, fBuffering,
  333. snd_pcm_format_name((_snd_pcm_format)fSampleFormat));
  334. }
  335. /**
  336. * print more detailled information on the audio device
  337. */
  338. int longinfo()
  339. {
  340. int err;
  341. snd_ctl_card_info_t* card_info;
  342. snd_ctl_t* ctl_handle;
  343. printf("Audio Interface Description :\n");
  344. printf("Sampling Frequency : %d, Sample Format : %s, buffering : %d\n",
  345. fFrequency, snd_pcm_format_name((_snd_pcm_format)fSampleFormat), fBuffering);
  346. printf("Software inputs : %2d, Software outputs : %2d\n", fSoftInputs, fSoftOutputs);
  347. printf("Hardware inputs : %2d, Hardware outputs : %2d\n", fCardInputs, fCardOutputs);
  348. printf("Channel inputs : %2d, Channel outputs : %2d\n", fChanInputs, fChanOutputs);
  349. // affichage des infos de la carte
  350. err = snd_ctl_open (&ctl_handle, fCardName, 0); check_error(err);
  351. snd_ctl_card_info_alloca (&card_info);
  352. err = snd_ctl_card_info(ctl_handle, card_info); check_error(err);
  353. printCardInfo(card_info);
  354. // affichage des infos liees aux streams d'entree-sortie
  355. if (fSoftInputs > 0) printHWParams(fInputParams);
  356. if (fSoftOutputs > 0) printHWParams(fOutputParams);
  357. return 0;
  358. }
  359. void printCardInfo(snd_ctl_card_info_t* ci)
  360. {
  361. printf("Card info (address : %p)\n", ci);
  362. printf("\tID = %s\n", snd_ctl_card_info_get_id(ci));
  363. printf("\tDriver = %s\n", snd_ctl_card_info_get_driver(ci));
  364. printf("\tName = %s\n", snd_ctl_card_info_get_name(ci));
  365. printf("\tLongName = %s\n", snd_ctl_card_info_get_longname(ci));
  366. printf("\tMixerName = %s\n", snd_ctl_card_info_get_mixername(ci));
  367. printf("\tComponents = %s\n", snd_ctl_card_info_get_components(ci));
  368. printf("--------------\n");
  369. }
  370. void printHWParams(snd_pcm_hw_params_t* params)
  371. {
  372. printf("HW Params info (address : %p)\n", params);
  373. #if 0
  374. printf("\tChannels = %d\n", snd_pcm_hw_params_get_channels(params));
  375. printf("\tFormat = %s\n", snd_pcm_format_name((_snd_pcm_format)snd_pcm_hw_params_get_format(params)));
  376. printf("\tAccess = %s\n", snd_pcm_access_name((_snd_pcm_access)snd_pcm_hw_params_get_access(params)));
  377. printf("\tRate = %d\n", snd_pcm_hw_params_get_rate(params, NULL));
  378. printf("\tPeriods = %d\n", snd_pcm_hw_params_get_periods(params, NULL));
  379. printf("\tPeriod size = %d\n", (int)snd_pcm_hw_params_get_period_size(params, NULL));
  380. printf("\tPeriod time = %d\n", snd_pcm_hw_params_get_period_time(params, NULL));
  381. printf("\tBuffer size = %d\n", (int)snd_pcm_hw_params_get_buffer_size(params));
  382. printf("\tBuffer time = %d\n", snd_pcm_hw_params_get_buffer_time(params, NULL));
  383. #endif
  384. printf("--------------\n");
  385. }
  386. };
  387. class JackAlsaIOAdapter : public JackIOAdapterInterface, public JackRunnableInterface
  388. {
  389. private:
  390. AudioInterface fAudioInterface;
  391. JackThread fThread;
  392. public:
  393. JackAlsaIOAdapter(int input, int output, jack_nframes_t buffer_size, jack_nframes_t sample_rate)
  394. :JackIOAdapterInterface(input, output, buffer_size, sample_rate)
  395. ,fThread(this)
  396. {
  397. fAudioInterface.fFrequency = sample_rate;
  398. fAudioInterface.fBuffering = buffer_size;
  399. fAudioInterface.fSoftInputs = input;
  400. fAudioInterface.fSoftOutputs = output;
  401. }
  402. ~JackAlsaIOAdapter()
  403. {}
  404. virtual int Open();
  405. virtual int Close();
  406. virtual int SetBufferSize(jack_nframes_t buffer_size);
  407. virtual bool Execute();
  408. };
  409. }
  410. #endif