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.

301 lines
11KB

  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. #if defined(HAVE_CONFIG_H)
  16. #include "config.h"
  17. #endif
  18. #include "JackPortAudioAdapter.h"
  19. #include "JackError.h"
  20. namespace Jack
  21. {
  22. int JackPortAudioAdapter::Render(const void* inputBuffer, void* outputBuffer,
  23. unsigned long framesPerBuffer,
  24. const PaStreamCallbackTimeInfo* timeInfo,
  25. PaStreamCallbackFlags statusFlags,
  26. void* userData)
  27. {
  28. JackPortAudioAdapter* adapter = static_cast<JackPortAudioAdapter*>(userData);
  29. float** paBuffer;
  30. float* buffer;
  31. bool failure = false;
  32. jack_nframes_t time1, time2;
  33. adapter->ResampleFactor(time1, time2);
  34. paBuffer = (float**)inputBuffer;
  35. for (int i = 0; i < adapter->fCaptureChannels; i++) {
  36. buffer = (float*)paBuffer[i];
  37. adapter->fCaptureRingBuffer[i]->SetRatio(time1, time2);
  38. if (adapter->fCaptureRingBuffer[i]->WriteResample(buffer, framesPerBuffer) < framesPerBuffer)
  39. failure = true;
  40. }
  41. paBuffer = (float**)outputBuffer;
  42. for (int i = 0; i < adapter->fPlaybackChannels; i++) {
  43. buffer = (float*)paBuffer[i];
  44. adapter->fPlaybackRingBuffer[i]->SetRatio(time2, time1);
  45. if (adapter->fPlaybackRingBuffer[i]->ReadResample(buffer, framesPerBuffer) < framesPerBuffer)
  46. failure = true;
  47. }
  48. #ifdef JACK_MONITOR
  49. adapter->fTable.Write(time1, time2, double(time1) / double(time2), double(time2) / double(time1),
  50. adapter->fCaptureRingBuffer[0]->ReadSpace(), adapter->fPlaybackRingBuffer[0]->WriteSpace());
  51. #endif
  52. // Reset all ringbuffers in case of failure
  53. if (failure) {
  54. jack_error("JackPortAudioAdapter::Render ringbuffer failure... reset");
  55. adapter->ResetRingBuffers();
  56. }
  57. return paContinue;
  58. }
  59. JackPortAudioAdapter::JackPortAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params)
  60. :JackAudioAdapterInterface(buffer_size, sample_rate)
  61. {
  62. jack_log ( "JackPortAudioAdapter::JackPortAudioAdapter buffer_size = %d, sample_rate = %d", buffer_size, sample_rate );
  63. const JSList* node;
  64. const jack_driver_param_t* param;
  65. int in_max = 0;
  66. int out_max = 0;
  67. fCaptureChannels = 0;
  68. fPlaybackChannels = 0;
  69. fInputDevice = Pa_GetDefaultInputDevice();
  70. fOutputDevice = Pa_GetDefaultOutputDevice();
  71. for (node = params; node; node = jack_slist_next(node)) {
  72. param = (const jack_driver_param_t*) node->data;
  73. switch (param->character) {
  74. case 'i':
  75. fCaptureChannels = param->value.ui;
  76. break;
  77. case 'o':
  78. fPlaybackChannels = param->value.ui;
  79. break;
  80. case 'C':
  81. if ( fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0 ) {
  82. jack_error ( "Can't use %s, taking default input device", param->value.str );
  83. fInputDevice = Pa_GetDefaultInputDevice();
  84. }
  85. break;
  86. case 'P':
  87. if ( fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0 ) {
  88. jack_error ( "Can't use %s, taking default output device", param->value.str );
  89. fOutputDevice = Pa_GetDefaultOutputDevice();
  90. }
  91. break;
  92. case 'r':
  93. SetAudioSampleRate(param->value.ui);
  94. break;
  95. case 'd':
  96. if ( fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0 ) {
  97. jack_error ( "Can't use %s, taking default input device", param->value.str );
  98. }
  99. if ( fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0 ) {
  100. jack_error ( "Can't use %s, taking default output device", param->value.str );
  101. }
  102. break;
  103. case 'l':
  104. fPaDevices.DisplayDevicesNames();
  105. break;
  106. }
  107. }
  108. //max channels
  109. if ( in_max == 0 )
  110. in_max = fPaDevices.GetDeviceInfo(fInputDevice)->maxInputChannels;
  111. if ( out_max == 0 )
  112. out_max = fPaDevices.GetDeviceInfo(fOutputDevice)->maxOutputChannels;
  113. //effective channels
  114. if ( ( fCaptureChannels == 0 ) || ( fCaptureChannels > in_max ) )
  115. fCaptureChannels = in_max;
  116. if ( ( fPlaybackChannels == 0 ) || ( fPlaybackChannels > out_max ) )
  117. fPlaybackChannels = out_max;
  118. }
  119. int JackPortAudioAdapter::Open()
  120. {
  121. PaError err;
  122. PaStreamParameters inputParameters;
  123. PaStreamParameters outputParameters;
  124. if (JackAudioAdapterInterface::Open() < 0)
  125. return -1;
  126. jack_log("JackPortAudioAdapter::Open fInputDevice = %d DeviceName %s", fInputDevice, fPaDevices.GetFullName(fInputDevice).c_str());
  127. jack_log("JackPortAudioAdapter::Open fOutputDevice = %d DeviceName %s", fOutputDevice, fPaDevices.GetFullName(fOutputDevice).c_str());
  128. jack_log("JackPortAudioAdapter::Open fBufferSize = %u fSampleRate %u", fBufferSize, fSampleRate);
  129. inputParameters.device = fInputDevice;
  130. inputParameters.channelCount = fCaptureChannels;
  131. inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output
  132. inputParameters.suggestedLatency = (fInputDevice != paNoDevice) // TODO: check how to setup this on ASIO
  133. ? fPaDevices.GetDeviceInfo(fInputDevice)->defaultLowInputLatency
  134. : 0;
  135. inputParameters.hostApiSpecificStreamInfo = NULL;
  136. outputParameters.device = fOutputDevice;
  137. outputParameters.channelCount = fPlaybackChannels;
  138. outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output
  139. outputParameters.suggestedLatency = (fOutputDevice != paNoDevice) // TODO: check how to setup this on ASIO
  140. ? fPaDevices.GetDeviceInfo(fOutputDevice)->defaultLowOutputLatency
  141. : 0;
  142. outputParameters.hostApiSpecificStreamInfo = NULL;
  143. err = Pa_OpenStream(&fStream,
  144. (fInputDevice == paNoDevice) ? 0 : &inputParameters,
  145. (fOutputDevice == paNoDevice) ? 0 : &outputParameters,
  146. fSampleRate,
  147. fBufferSize,
  148. paNoFlag, // Clipping is on...
  149. Render,
  150. this);
  151. if (err != paNoError) {
  152. jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err));
  153. return -1;
  154. }
  155. err = Pa_StartStream(fStream);
  156. if (err != paNoError) {
  157. jack_error("Pa_StartStream error = %s", Pa_GetErrorText(err));
  158. return -1;
  159. }
  160. jack_log("JackPortAudioAdapter::Open OK");
  161. return 0;
  162. }
  163. int JackPortAudioAdapter::Close()
  164. {
  165. #ifdef JACK_MONITOR
  166. fTable.Save();
  167. #endif
  168. jack_log("JackPortAudioAdapter::Close");
  169. Pa_StopStream(fStream);
  170. jack_log("JackPortAudioAdapter:: Pa_StopStream");
  171. Pa_CloseStream(fStream);
  172. jack_log("JackPortAudioAdapter:: Pa_CloseStream");
  173. return JackAudioAdapterInterface::Close();
  174. }
  175. int JackPortAudioAdapter::SetBufferSize(jack_nframes_t buffer_size)
  176. {
  177. JackAudioAdapterInterface::SetBufferSize(buffer_size);
  178. Close();
  179. return Open();
  180. }
  181. } // namespace
  182. #ifdef __cplusplus
  183. extern "C"
  184. {
  185. #endif
  186. EXPORT jack_driver_desc_t* jack_get_descriptor()
  187. {
  188. jack_driver_desc_t *desc;
  189. unsigned int i;
  190. desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t));
  191. strcpy(desc->name, "portaudio-adapter");
  192. desc->nparams = 7;
  193. desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t));
  194. i = 0;
  195. strcpy(desc->params[i].name, "inchannels");
  196. desc->params[i].character = 'i';
  197. desc->params[i].type = JackDriverParamInt;
  198. desc->params[i].value.ui = 0;
  199. strcpy(desc->params[i].short_desc, "Maximum number of input channels");
  200. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  201. i++;
  202. strcpy(desc->params[i].name, "outchannels");
  203. desc->params[i].character = 'o';
  204. desc->params[i].type = JackDriverParamInt;
  205. desc->params[i].value.ui = 0;
  206. strcpy(desc->params[i].short_desc, "Maximum number of output channels");
  207. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  208. i++;
  209. strcpy(desc->params[i].name, "capture");
  210. desc->params[i].character = 'C';
  211. desc->params[i].type = JackDriverParamString;
  212. strcpy(desc->params[i].value.str, "default input device");
  213. strcpy(desc->params[i].short_desc, "Provide capture ports. Optionally set PortAudio device name");
  214. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  215. i++;
  216. strcpy(desc->params[i].name, "playback");
  217. desc->params[i].character = 'P';
  218. desc->params[i].type = JackDriverParamString;
  219. strcpy(desc->params[i].value.str, "default output device");
  220. strcpy(desc->params[i].short_desc, "Provide playback ports. Optionally set PortAudio device name");
  221. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  222. i++;
  223. strcpy(desc->params[i].name, "rate");
  224. desc->params[i].character = 'r';
  225. desc->params[i].type = JackDriverParamUInt;
  226. desc->params[i].value.ui = 44100U;
  227. strcpy(desc->params[i].short_desc, "Sample rate");
  228. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  229. i++;
  230. strcpy(desc->params[i].name, "device");
  231. desc->params[i].character = 'd';
  232. desc->params[i].type = JackDriverParamString;
  233. desc->params[i].value.ui = 128U;
  234. strcpy(desc->params[i].value.str, "default device");
  235. strcpy(desc->params[i].short_desc, "PortAudio device name");
  236. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  237. i++;
  238. strcpy(desc->params[i].name, "list-devices");
  239. desc->params[i].character = 'l';
  240. desc->params[i].type = JackDriverParamBool;
  241. desc->params[i].value.i = TRUE;
  242. strcpy(desc->params[i].short_desc, "Display available PortAudio devices");
  243. strcpy(desc->params[i].long_desc, desc->params[i].short_desc);
  244. return desc;
  245. }
  246. #ifdef __cplusplus
  247. }
  248. #endif