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.

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