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.

254 lines
9.4KB

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