pa_process.c 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830
  1. /*
  2. * $Id: pa_process.c 1913 2013-11-18 11:42:27Z gineera $
  3. * Portable Audio I/O Library
  4. * streamCallback <-> host buffer processing adapter
  5. *
  6. * Based on the Open Source API proposed by Ross Bencina
  7. * Copyright (c) 1999-2002 Ross Bencina, Phil Burk
  8. *
  9. * Permission is hereby granted, free of charge, to any person obtaining
  10. * a copy of this software and associated documentation files
  11. * (the "Software"), to deal in the Software without restriction,
  12. * including without limitation the rights to use, copy, modify, merge,
  13. * publish, distribute, sublicense, and/or sell copies of the Software,
  14. * and to permit persons to whom the Software is furnished to do so,
  15. * subject to the following conditions:
  16. *
  17. * The above copyright notice and this permission notice shall be
  18. * included in all copies or substantial portions of the Software.
  19. *
  20. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  21. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  22. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  23. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR
  24. * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  25. * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
  26. * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  27. */
  28. /*
  29. * The text above constitutes the entire PortAudio license; however,
  30. * the PortAudio community also makes the following non-binding requests:
  31. *
  32. * Any person wishing to distribute modifications to the Software is
  33. * requested to send the modifications to the original developer so that
  34. * they can be incorporated into the canonical version. It is also
  35. * requested that these non-binding requests be included along with the
  36. * license above.
  37. */
  38. /** @file
  39. @ingroup common_src
  40. @brief Buffer Processor implementation.
  41. */
  42. #include <assert.h>
  43. #include <string.h> /* memset() */
  44. #include "pa_process.h"
  45. #include "pa_util.h"
  46. #define PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_ 1024
  47. #define PA_MIN_( a, b ) ( ((a)<(b)) ? (a) : (b) )
  48. /* greatest common divisor - PGCD in French */
  49. static unsigned long GCD( unsigned long a, unsigned long b )
  50. {
  51. return (b==0) ? a : GCD( b, a%b);
  52. }
  53. /* least common multiple - PPCM in French */
  54. static unsigned long LCM( unsigned long a, unsigned long b )
  55. {
  56. return (a*b) / GCD(a,b);
  57. }
  58. #define PA_MAX_( a, b ) (((a) > (b)) ? (a) : (b))
  59. static unsigned long CalculateFrameShift( unsigned long M, unsigned long N )
  60. {
  61. unsigned long result = 0;
  62. unsigned long i;
  63. unsigned long lcm;
  64. assert( M > 0 );
  65. assert( N > 0 );
  66. lcm = LCM( M, N );
  67. for( i = M; i < lcm; i += M )
  68. result = PA_MAX_( result, i % N );
  69. return result;
  70. }
  71. PaError PaUtil_InitializeBufferProcessor( PaUtilBufferProcessor* bp,
  72. int inputChannelCount, PaSampleFormat userInputSampleFormat,
  73. PaSampleFormat hostInputSampleFormat,
  74. int outputChannelCount, PaSampleFormat userOutputSampleFormat,
  75. PaSampleFormat hostOutputSampleFormat,
  76. double sampleRate,
  77. PaStreamFlags streamFlags,
  78. unsigned long framesPerUserBuffer,
  79. unsigned long framesPerHostBuffer,
  80. PaUtilHostBufferSizeMode hostBufferSizeMode,
  81. PaStreamCallback *streamCallback, void *userData )
  82. {
  83. PaError result = paNoError;
  84. PaError bytesPerSample;
  85. unsigned long tempInputBufferSize, tempOutputBufferSize;
  86. PaStreamFlags tempInputStreamFlags;
  87. if( streamFlags & paNeverDropInput )
  88. {
  89. /* paNeverDropInput is only valid for full-duplex callback streams, with an unspecified number of frames per buffer. */
  90. if( !streamCallback || !(inputChannelCount > 0 && outputChannelCount > 0) ||
  91. framesPerUserBuffer != paFramesPerBufferUnspecified )
  92. return paInvalidFlag;
  93. }
  94. /* initialize buffer ptrs to zero so they can be freed if necessary in error */
  95. bp->tempInputBuffer = 0;
  96. bp->tempInputBufferPtrs = 0;
  97. bp->tempOutputBuffer = 0;
  98. bp->tempOutputBufferPtrs = 0;
  99. bp->framesPerUserBuffer = framesPerUserBuffer;
  100. bp->framesPerHostBuffer = framesPerHostBuffer;
  101. bp->inputChannelCount = inputChannelCount;
  102. bp->outputChannelCount = outputChannelCount;
  103. bp->hostBufferSizeMode = hostBufferSizeMode;
  104. bp->hostInputChannels[0] = bp->hostInputChannels[1] = 0;
  105. bp->hostOutputChannels[0] = bp->hostOutputChannels[1] = 0;
  106. if( framesPerUserBuffer == 0 ) /* streamCallback will accept any buffer size */
  107. {
  108. bp->useNonAdaptingProcess = 1;
  109. bp->initialFramesInTempInputBuffer = 0;
  110. bp->initialFramesInTempOutputBuffer = 0;
  111. if( hostBufferSizeMode == paUtilFixedHostBufferSize
  112. || hostBufferSizeMode == paUtilBoundedHostBufferSize )
  113. {
  114. bp->framesPerTempBuffer = framesPerHostBuffer;
  115. }
  116. else /* unknown host buffer size */
  117. {
  118. bp->framesPerTempBuffer = PA_FRAMES_PER_TEMP_BUFFER_WHEN_HOST_BUFFER_SIZE_IS_UNKNOWN_;
  119. }
  120. }
  121. else
  122. {
  123. bp->framesPerTempBuffer = framesPerUserBuffer;
  124. if( hostBufferSizeMode == paUtilFixedHostBufferSize
  125. && framesPerHostBuffer % framesPerUserBuffer == 0 )
  126. {
  127. bp->useNonAdaptingProcess = 1;
  128. bp->initialFramesInTempInputBuffer = 0;
  129. bp->initialFramesInTempOutputBuffer = 0;
  130. }
  131. else
  132. {
  133. bp->useNonAdaptingProcess = 0;
  134. if( inputChannelCount > 0 && outputChannelCount > 0 )
  135. {
  136. /* full duplex */
  137. if( hostBufferSizeMode == paUtilFixedHostBufferSize )
  138. {
  139. unsigned long frameShift =
  140. CalculateFrameShift( framesPerHostBuffer, framesPerUserBuffer );
  141. if( framesPerUserBuffer > framesPerHostBuffer )
  142. {
  143. bp->initialFramesInTempInputBuffer = frameShift;
  144. bp->initialFramesInTempOutputBuffer = 0;
  145. }
  146. else
  147. {
  148. bp->initialFramesInTempInputBuffer = 0;
  149. bp->initialFramesInTempOutputBuffer = frameShift;
  150. }
  151. }
  152. else /* variable host buffer size, add framesPerUserBuffer latency */
  153. {
  154. bp->initialFramesInTempInputBuffer = 0;
  155. bp->initialFramesInTempOutputBuffer = framesPerUserBuffer;
  156. }
  157. }
  158. else
  159. {
  160. /* half duplex */
  161. bp->initialFramesInTempInputBuffer = 0;
  162. bp->initialFramesInTempOutputBuffer = 0;
  163. }
  164. }
  165. }
  166. bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
  167. bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
  168. if( inputChannelCount > 0 )
  169. {
  170. bytesPerSample = Pa_GetSampleSize( hostInputSampleFormat );
  171. if( bytesPerSample > 0 )
  172. {
  173. bp->bytesPerHostInputSample = bytesPerSample;
  174. }
  175. else
  176. {
  177. result = bytesPerSample;
  178. goto error;
  179. }
  180. bytesPerSample = Pa_GetSampleSize( userInputSampleFormat );
  181. if( bytesPerSample > 0 )
  182. {
  183. bp->bytesPerUserInputSample = bytesPerSample;
  184. }
  185. else
  186. {
  187. result = bytesPerSample;
  188. goto error;
  189. }
  190. /* Under the assumption that no ADC in existence delivers better than 24bits resolution,
  191. we disable dithering when host input format is paInt32 and user format is paInt24,
  192. since the host samples will just be padded with zeros anyway. */
  193. tempInputStreamFlags = streamFlags;
  194. if( !(tempInputStreamFlags & paDitherOff) /* dither is on */
  195. && (hostInputSampleFormat & paInt32) /* host input format is int32 */
  196. && (userInputSampleFormat & paInt24) /* user requested format is int24 */ ){
  197. tempInputStreamFlags = tempInputStreamFlags | paDitherOff;
  198. }
  199. bp->inputConverter =
  200. PaUtil_SelectConverter( hostInputSampleFormat, userInputSampleFormat, tempInputStreamFlags );
  201. bp->inputZeroer = PaUtil_SelectZeroer( userInputSampleFormat );
  202. bp->userInputIsInterleaved = (userInputSampleFormat & paNonInterleaved)?0:1;
  203. bp->hostInputIsInterleaved = (hostInputSampleFormat & paNonInterleaved)?0:1;
  204. bp->userInputSampleFormatIsEqualToHost = ((userInputSampleFormat & ~paNonInterleaved) == (hostInputSampleFormat & ~paNonInterleaved));
  205. tempInputBufferSize =
  206. bp->framesPerTempBuffer * bp->bytesPerUserInputSample * inputChannelCount;
  207. bp->tempInputBuffer = PaUtil_AllocateMemory( tempInputBufferSize );
  208. if( bp->tempInputBuffer == 0 )
  209. {
  210. result = paInsufficientMemory;
  211. goto error;
  212. }
  213. if( bp->framesInTempInputBuffer > 0 )
  214. memset( bp->tempInputBuffer, 0, tempInputBufferSize );
  215. if( userInputSampleFormat & paNonInterleaved )
  216. {
  217. bp->tempInputBufferPtrs =
  218. (void **)PaUtil_AllocateMemory( sizeof(void*)*inputChannelCount );
  219. if( bp->tempInputBufferPtrs == 0 )
  220. {
  221. result = paInsufficientMemory;
  222. goto error;
  223. }
  224. }
  225. bp->hostInputChannels[0] = (PaUtilChannelDescriptor*)
  226. PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor) * inputChannelCount * 2);
  227. if( bp->hostInputChannels[0] == 0 )
  228. {
  229. result = paInsufficientMemory;
  230. goto error;
  231. }
  232. bp->hostInputChannels[1] = &bp->hostInputChannels[0][inputChannelCount];
  233. }
  234. if( outputChannelCount > 0 )
  235. {
  236. bytesPerSample = Pa_GetSampleSize( hostOutputSampleFormat );
  237. if( bytesPerSample > 0 )
  238. {
  239. bp->bytesPerHostOutputSample = bytesPerSample;
  240. }
  241. else
  242. {
  243. result = bytesPerSample;
  244. goto error;
  245. }
  246. bytesPerSample = Pa_GetSampleSize( userOutputSampleFormat );
  247. if( bytesPerSample > 0 )
  248. {
  249. bp->bytesPerUserOutputSample = bytesPerSample;
  250. }
  251. else
  252. {
  253. result = bytesPerSample;
  254. goto error;
  255. }
  256. bp->outputConverter =
  257. PaUtil_SelectConverter( userOutputSampleFormat, hostOutputSampleFormat, streamFlags );
  258. bp->outputZeroer = PaUtil_SelectZeroer( hostOutputSampleFormat );
  259. bp->userOutputIsInterleaved = (userOutputSampleFormat & paNonInterleaved)?0:1;
  260. bp->hostOutputIsInterleaved = (hostOutputSampleFormat & paNonInterleaved)?0:1;
  261. bp->userOutputSampleFormatIsEqualToHost = ((userOutputSampleFormat & ~paNonInterleaved) == (hostOutputSampleFormat & ~paNonInterleaved));
  262. tempOutputBufferSize =
  263. bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * outputChannelCount;
  264. bp->tempOutputBuffer = PaUtil_AllocateMemory( tempOutputBufferSize );
  265. if( bp->tempOutputBuffer == 0 )
  266. {
  267. result = paInsufficientMemory;
  268. goto error;
  269. }
  270. if( bp->framesInTempOutputBuffer > 0 )
  271. memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
  272. if( userOutputSampleFormat & paNonInterleaved )
  273. {
  274. bp->tempOutputBufferPtrs =
  275. (void **)PaUtil_AllocateMemory( sizeof(void*)*outputChannelCount );
  276. if( bp->tempOutputBufferPtrs == 0 )
  277. {
  278. result = paInsufficientMemory;
  279. goto error;
  280. }
  281. }
  282. bp->hostOutputChannels[0] = (PaUtilChannelDescriptor*)
  283. PaUtil_AllocateMemory( sizeof(PaUtilChannelDescriptor)*outputChannelCount * 2 );
  284. if( bp->hostOutputChannels[0] == 0 )
  285. {
  286. result = paInsufficientMemory;
  287. goto error;
  288. }
  289. bp->hostOutputChannels[1] = &bp->hostOutputChannels[0][outputChannelCount];
  290. }
  291. PaUtil_InitializeTriangularDitherState( &bp->ditherGenerator );
  292. bp->samplePeriod = 1. / sampleRate;
  293. bp->streamCallback = streamCallback;
  294. bp->userData = userData;
  295. return result;
  296. error:
  297. if( bp->tempInputBuffer )
  298. PaUtil_FreeMemory( bp->tempInputBuffer );
  299. if( bp->tempInputBufferPtrs )
  300. PaUtil_FreeMemory( bp->tempInputBufferPtrs );
  301. if( bp->hostInputChannels[0] )
  302. PaUtil_FreeMemory( bp->hostInputChannels[0] );
  303. if( bp->tempOutputBuffer )
  304. PaUtil_FreeMemory( bp->tempOutputBuffer );
  305. if( bp->tempOutputBufferPtrs )
  306. PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
  307. if( bp->hostOutputChannels[0] )
  308. PaUtil_FreeMemory( bp->hostOutputChannels[0] );
  309. return result;
  310. }
  311. void PaUtil_TerminateBufferProcessor( PaUtilBufferProcessor* bp )
  312. {
  313. if( bp->tempInputBuffer )
  314. PaUtil_FreeMemory( bp->tempInputBuffer );
  315. if( bp->tempInputBufferPtrs )
  316. PaUtil_FreeMemory( bp->tempInputBufferPtrs );
  317. if( bp->hostInputChannels[0] )
  318. PaUtil_FreeMemory( bp->hostInputChannels[0] );
  319. if( bp->tempOutputBuffer )
  320. PaUtil_FreeMemory( bp->tempOutputBuffer );
  321. if( bp->tempOutputBufferPtrs )
  322. PaUtil_FreeMemory( bp->tempOutputBufferPtrs );
  323. if( bp->hostOutputChannels[0] )
  324. PaUtil_FreeMemory( bp->hostOutputChannels[0] );
  325. }
  326. void PaUtil_ResetBufferProcessor( PaUtilBufferProcessor* bp )
  327. {
  328. unsigned long tempInputBufferSize, tempOutputBufferSize;
  329. bp->framesInTempInputBuffer = bp->initialFramesInTempInputBuffer;
  330. bp->framesInTempOutputBuffer = bp->initialFramesInTempOutputBuffer;
  331. if( bp->framesInTempInputBuffer > 0 )
  332. {
  333. tempInputBufferSize =
  334. bp->framesPerTempBuffer * bp->bytesPerUserInputSample * bp->inputChannelCount;
  335. memset( bp->tempInputBuffer, 0, tempInputBufferSize );
  336. }
  337. if( bp->framesInTempOutputBuffer > 0 )
  338. {
  339. tempOutputBufferSize =
  340. bp->framesPerTempBuffer * bp->bytesPerUserOutputSample * bp->outputChannelCount;
  341. memset( bp->tempOutputBuffer, 0, tempOutputBufferSize );
  342. }
  343. }
  344. unsigned long PaUtil_GetBufferProcessorInputLatencyFrames( PaUtilBufferProcessor* bp )
  345. {
  346. return bp->initialFramesInTempInputBuffer;
  347. }
  348. unsigned long PaUtil_GetBufferProcessorOutputLatencyFrames( PaUtilBufferProcessor* bp )
  349. {
  350. return bp->initialFramesInTempOutputBuffer;
  351. }
  352. void PaUtil_SetInputFrameCount( PaUtilBufferProcessor* bp,
  353. unsigned long frameCount )
  354. {
  355. if( frameCount == 0 )
  356. bp->hostInputFrameCount[0] = bp->framesPerHostBuffer;
  357. else
  358. bp->hostInputFrameCount[0] = frameCount;
  359. }
  360. void PaUtil_SetNoInput( PaUtilBufferProcessor* bp )
  361. {
  362. assert( bp->inputChannelCount > 0 );
  363. bp->hostInputChannels[0][0].data = 0;
  364. }
  365. void PaUtil_SetInputChannel( PaUtilBufferProcessor* bp,
  366. unsigned int channel, void *data, unsigned int stride )
  367. {
  368. assert( channel < bp->inputChannelCount );
  369. bp->hostInputChannels[0][channel].data = data;
  370. bp->hostInputChannels[0][channel].stride = stride;
  371. }
  372. void PaUtil_SetInterleavedInputChannels( PaUtilBufferProcessor* bp,
  373. unsigned int firstChannel, void *data, unsigned int channelCount )
  374. {
  375. unsigned int i;
  376. unsigned int channel = firstChannel;
  377. unsigned char *p = (unsigned char*)data;
  378. if( channelCount == 0 )
  379. channelCount = bp->inputChannelCount;
  380. assert( firstChannel < bp->inputChannelCount );
  381. assert( firstChannel + channelCount <= bp->inputChannelCount );
  382. assert( bp->hostInputIsInterleaved );
  383. for( i=0; i< channelCount; ++i )
  384. {
  385. bp->hostInputChannels[0][channel+i].data = p;
  386. p += bp->bytesPerHostInputSample;
  387. bp->hostInputChannels[0][channel+i].stride = channelCount;
  388. }
  389. }
  390. void PaUtil_SetNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
  391. unsigned int channel, void *data )
  392. {
  393. assert( channel < bp->inputChannelCount );
  394. assert( !bp->hostInputIsInterleaved );
  395. bp->hostInputChannels[0][channel].data = data;
  396. bp->hostInputChannels[0][channel].stride = 1;
  397. }
  398. void PaUtil_Set2ndInputFrameCount( PaUtilBufferProcessor* bp,
  399. unsigned long frameCount )
  400. {
  401. bp->hostInputFrameCount[1] = frameCount;
  402. }
  403. void PaUtil_Set2ndInputChannel( PaUtilBufferProcessor* bp,
  404. unsigned int channel, void *data, unsigned int stride )
  405. {
  406. assert( channel < bp->inputChannelCount );
  407. bp->hostInputChannels[1][channel].data = data;
  408. bp->hostInputChannels[1][channel].stride = stride;
  409. }
  410. void PaUtil_Set2ndInterleavedInputChannels( PaUtilBufferProcessor* bp,
  411. unsigned int firstChannel, void *data, unsigned int channelCount )
  412. {
  413. unsigned int i;
  414. unsigned int channel = firstChannel;
  415. unsigned char *p = (unsigned char*)data;
  416. if( channelCount == 0 )
  417. channelCount = bp->inputChannelCount;
  418. assert( firstChannel < bp->inputChannelCount );
  419. assert( firstChannel + channelCount <= bp->inputChannelCount );
  420. assert( bp->hostInputIsInterleaved );
  421. for( i=0; i< channelCount; ++i )
  422. {
  423. bp->hostInputChannels[1][channel+i].data = p;
  424. p += bp->bytesPerHostInputSample;
  425. bp->hostInputChannels[1][channel+i].stride = channelCount;
  426. }
  427. }
  428. void PaUtil_Set2ndNonInterleavedInputChannel( PaUtilBufferProcessor* bp,
  429. unsigned int channel, void *data )
  430. {
  431. assert( channel < bp->inputChannelCount );
  432. assert( !bp->hostInputIsInterleaved );
  433. bp->hostInputChannels[1][channel].data = data;
  434. bp->hostInputChannels[1][channel].stride = 1;
  435. }
  436. void PaUtil_SetOutputFrameCount( PaUtilBufferProcessor* bp,
  437. unsigned long frameCount )
  438. {
  439. if( frameCount == 0 )
  440. bp->hostOutputFrameCount[0] = bp->framesPerHostBuffer;
  441. else
  442. bp->hostOutputFrameCount[0] = frameCount;
  443. }
  444. void PaUtil_SetNoOutput( PaUtilBufferProcessor* bp )
  445. {
  446. assert( bp->outputChannelCount > 0 );
  447. bp->hostOutputChannels[0][0].data = 0;
  448. /* note that only NonAdaptingProcess is able to deal with no output at this stage. not implemented for AdaptingProcess */
  449. }
  450. void PaUtil_SetOutputChannel( PaUtilBufferProcessor* bp,
  451. unsigned int channel, void *data, unsigned int stride )
  452. {
  453. assert( channel < bp->outputChannelCount );
  454. assert( data != NULL );
  455. bp->hostOutputChannels[0][channel].data = data;
  456. bp->hostOutputChannels[0][channel].stride = stride;
  457. }
  458. void PaUtil_SetInterleavedOutputChannels( PaUtilBufferProcessor* bp,
  459. unsigned int firstChannel, void *data, unsigned int channelCount )
  460. {
  461. unsigned int i;
  462. unsigned int channel = firstChannel;
  463. unsigned char *p = (unsigned char*)data;
  464. if( channelCount == 0 )
  465. channelCount = bp->outputChannelCount;
  466. assert( firstChannel < bp->outputChannelCount );
  467. assert( firstChannel + channelCount <= bp->outputChannelCount );
  468. assert( bp->hostOutputIsInterleaved );
  469. for( i=0; i< channelCount; ++i )
  470. {
  471. PaUtil_SetOutputChannel( bp, channel + i, p, channelCount );
  472. p += bp->bytesPerHostOutputSample;
  473. }
  474. }
  475. void PaUtil_SetNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
  476. unsigned int channel, void *data )
  477. {
  478. assert( channel < bp->outputChannelCount );
  479. assert( !bp->hostOutputIsInterleaved );
  480. PaUtil_SetOutputChannel( bp, channel, data, 1 );
  481. }
  482. void PaUtil_Set2ndOutputFrameCount( PaUtilBufferProcessor* bp,
  483. unsigned long frameCount )
  484. {
  485. bp->hostOutputFrameCount[1] = frameCount;
  486. }
  487. void PaUtil_Set2ndOutputChannel( PaUtilBufferProcessor* bp,
  488. unsigned int channel, void *data, unsigned int stride )
  489. {
  490. assert( channel < bp->outputChannelCount );
  491. assert( data != NULL );
  492. bp->hostOutputChannels[1][channel].data = data;
  493. bp->hostOutputChannels[1][channel].stride = stride;
  494. }
  495. void PaUtil_Set2ndInterleavedOutputChannels( PaUtilBufferProcessor* bp,
  496. unsigned int firstChannel, void *data, unsigned int channelCount )
  497. {
  498. unsigned int i;
  499. unsigned int channel = firstChannel;
  500. unsigned char *p = (unsigned char*)data;
  501. if( channelCount == 0 )
  502. channelCount = bp->outputChannelCount;
  503. assert( firstChannel < bp->outputChannelCount );
  504. assert( firstChannel + channelCount <= bp->outputChannelCount );
  505. assert( bp->hostOutputIsInterleaved );
  506. for( i=0; i< channelCount; ++i )
  507. {
  508. PaUtil_Set2ndOutputChannel( bp, channel + i, p, channelCount );
  509. p += bp->bytesPerHostOutputSample;
  510. }
  511. }
  512. void PaUtil_Set2ndNonInterleavedOutputChannel( PaUtilBufferProcessor* bp,
  513. unsigned int channel, void *data )
  514. {
  515. assert( channel < bp->outputChannelCount );
  516. assert( !bp->hostOutputIsInterleaved );
  517. PaUtil_Set2ndOutputChannel( bp, channel, data, 1 );
  518. }
  519. void PaUtil_BeginBufferProcessing( PaUtilBufferProcessor* bp,
  520. PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags callbackStatusFlags )
  521. {
  522. bp->timeInfo = timeInfo;
  523. /* the first streamCallback will be called to process samples which are
  524. currently in the input buffer before the ones starting at the timeInfo time */
  525. bp->timeInfo->inputBufferAdcTime -= bp->framesInTempInputBuffer * bp->samplePeriod;
  526. /* We just pass through timeInfo->currentTime provided by the caller. This is
  527. not strictly conformant to the word of the spec, since the buffer processor
  528. might call the callback multiple times, and we never refresh currentTime. */
  529. /* the first streamCallback will be called to generate samples which will be
  530. outputted after the frames currently in the output buffer have been
  531. outputted. */
  532. bp->timeInfo->outputBufferDacTime += bp->framesInTempOutputBuffer * bp->samplePeriod;
  533. bp->callbackStatusFlags = callbackStatusFlags;
  534. bp->hostInputFrameCount[1] = 0;
  535. bp->hostOutputFrameCount[1] = 0;
  536. }
  537. /*
  538. NonAdaptingProcess() is a simple buffer copying adaptor that can handle
  539. both full and half duplex copies. It processes framesToProcess frames,
  540. broken into blocks bp->framesPerTempBuffer long.
  541. This routine can be used when the streamCallback doesn't care what length
  542. the buffers are, or when framesToProcess is an integer multiple of
  543. bp->framesPerTempBuffer, in which case streamCallback will always be called
  544. with bp->framesPerTempBuffer samples.
  545. */
  546. static unsigned long NonAdaptingProcess( PaUtilBufferProcessor *bp,
  547. int *streamCallbackResult,
  548. PaUtilChannelDescriptor *hostInputChannels,
  549. PaUtilChannelDescriptor *hostOutputChannels,
  550. unsigned long framesToProcess )
  551. {
  552. void *userInput, *userOutput;
  553. unsigned char *srcBytePtr, *destBytePtr;
  554. unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
  555. unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
  556. unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
  557. unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
  558. unsigned int i;
  559. unsigned long frameCount;
  560. unsigned long framesToGo = framesToProcess;
  561. unsigned long framesProcessed = 0;
  562. int skipOutputConvert = 0;
  563. int skipInputConvert = 0;
  564. if( *streamCallbackResult == paContinue )
  565. {
  566. do
  567. {
  568. frameCount = PA_MIN_( bp->framesPerTempBuffer, framesToGo );
  569. /* configure user input buffer and convert input data (host -> user) */
  570. if( bp->inputChannelCount == 0 )
  571. {
  572. /* no input */
  573. userInput = 0;
  574. }
  575. else /* there are input channels */
  576. {
  577. destBytePtr = (unsigned char *)bp->tempInputBuffer;
  578. if( bp->userInputIsInterleaved )
  579. {
  580. destSampleStrideSamples = bp->inputChannelCount;
  581. destChannelStrideBytes = bp->bytesPerUserInputSample;
  582. /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved,
  583. * or if the number of channels differs between the host (set in stride) and the user */
  584. if( bp->userInputSampleFormatIsEqualToHost && bp->hostInputIsInterleaved
  585. && bp->hostInputChannels[0][0].data && bp->inputChannelCount == hostInputChannels[0].stride )
  586. {
  587. userInput = hostInputChannels[0].data;
  588. destBytePtr = (unsigned char *)hostInputChannels[0].data;
  589. skipInputConvert = 1;
  590. }
  591. else
  592. {
  593. userInput = bp->tempInputBuffer;
  594. }
  595. }
  596. else /* user input is not interleaved */
  597. {
  598. destSampleStrideSamples = 1;
  599. destChannelStrideBytes = frameCount * bp->bytesPerUserInputSample;
  600. /* setup non-interleaved ptrs */
  601. if( bp->userInputSampleFormatIsEqualToHost && !bp->hostInputIsInterleaved && bp->hostInputChannels[0][0].data )
  602. {
  603. for( i=0; i<bp->inputChannelCount; ++i )
  604. {
  605. bp->tempInputBufferPtrs[i] = hostInputChannels[i].data;
  606. }
  607. skipInputConvert = 1;
  608. }
  609. else
  610. {
  611. for( i=0; i<bp->inputChannelCount; ++i )
  612. {
  613. bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
  614. i * bp->bytesPerUserInputSample * frameCount;
  615. }
  616. }
  617. userInput = bp->tempInputBufferPtrs;
  618. }
  619. if( !bp->hostInputChannels[0][0].data )
  620. {
  621. /* no input was supplied (see PaUtil_SetNoInput), so
  622. zero the input buffer */
  623. for( i=0; i<bp->inputChannelCount; ++i )
  624. {
  625. bp->inputZeroer( destBytePtr, destSampleStrideSamples, frameCount );
  626. destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
  627. }
  628. }
  629. else
  630. {
  631. if( skipInputConvert )
  632. {
  633. for( i=0; i<bp->inputChannelCount; ++i )
  634. {
  635. /* advance src ptr for next iteration */
  636. hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
  637. frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
  638. }
  639. }
  640. else
  641. {
  642. for( i=0; i<bp->inputChannelCount; ++i )
  643. {
  644. bp->inputConverter( destBytePtr, destSampleStrideSamples,
  645. hostInputChannels[i].data,
  646. hostInputChannels[i].stride,
  647. frameCount, &bp->ditherGenerator );
  648. destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
  649. /* advance src ptr for next iteration */
  650. hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
  651. frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
  652. }
  653. }
  654. }
  655. }
  656. /* configure user output buffer */
  657. if( bp->outputChannelCount == 0 )
  658. {
  659. /* no output */
  660. userOutput = 0;
  661. }
  662. else /* there are output channels */
  663. {
  664. if( bp->userOutputIsInterleaved )
  665. {
  666. /* process host buffer directly, or use temp buffer if formats differ or host buffer non-interleaved */
  667. if( bp->userOutputSampleFormatIsEqualToHost && bp->hostOutputIsInterleaved )
  668. {
  669. userOutput = hostOutputChannels[0].data;
  670. skipOutputConvert = 1;
  671. }
  672. else
  673. {
  674. userOutput = bp->tempOutputBuffer;
  675. }
  676. }
  677. else /* user output is not interleaved */
  678. {
  679. if( bp->userOutputSampleFormatIsEqualToHost && !bp->hostOutputIsInterleaved )
  680. {
  681. for( i=0; i<bp->outputChannelCount; ++i )
  682. {
  683. bp->tempOutputBufferPtrs[i] = hostOutputChannels[i].data;
  684. }
  685. skipOutputConvert = 1;
  686. }
  687. else
  688. {
  689. for( i=0; i<bp->outputChannelCount; ++i )
  690. {
  691. bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
  692. i * bp->bytesPerUserOutputSample * frameCount;
  693. }
  694. }
  695. userOutput = bp->tempOutputBufferPtrs;
  696. }
  697. }
  698. *streamCallbackResult = bp->streamCallback( userInput, userOutput,
  699. frameCount, bp->timeInfo, bp->callbackStatusFlags, bp->userData );
  700. if( *streamCallbackResult == paAbort )
  701. {
  702. /* callback returned paAbort, don't advance framesProcessed
  703. and framesToGo, they will be handled below */
  704. }
  705. else
  706. {
  707. bp->timeInfo->inputBufferAdcTime += frameCount * bp->samplePeriod;
  708. bp->timeInfo->outputBufferDacTime += frameCount * bp->samplePeriod;
  709. /* convert output data (user -> host) */
  710. if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
  711. {
  712. if( skipOutputConvert )
  713. {
  714. for( i=0; i<bp->outputChannelCount; ++i )
  715. {
  716. /* advance dest ptr for next iteration */
  717. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  718. frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  719. }
  720. }
  721. else
  722. {
  723. srcBytePtr = (unsigned char *)bp->tempOutputBuffer;
  724. if( bp->userOutputIsInterleaved )
  725. {
  726. srcSampleStrideSamples = bp->outputChannelCount;
  727. srcChannelStrideBytes = bp->bytesPerUserOutputSample;
  728. }
  729. else /* user output is not interleaved */
  730. {
  731. srcSampleStrideSamples = 1;
  732. srcChannelStrideBytes = frameCount * bp->bytesPerUserOutputSample;
  733. }
  734. for( i=0; i<bp->outputChannelCount; ++i )
  735. {
  736. bp->outputConverter( hostOutputChannels[i].data,
  737. hostOutputChannels[i].stride,
  738. srcBytePtr, srcSampleStrideSamples,
  739. frameCount, &bp->ditherGenerator );
  740. srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
  741. /* advance dest ptr for next iteration */
  742. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  743. frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  744. }
  745. }
  746. }
  747. framesProcessed += frameCount;
  748. framesToGo -= frameCount;
  749. }
  750. }
  751. while( framesToGo > 0 && *streamCallbackResult == paContinue );
  752. }
  753. if( framesToGo > 0 )
  754. {
  755. /* zero any remaining frames output. There will only be remaining frames
  756. if the callback has returned paComplete or paAbort */
  757. frameCount = framesToGo;
  758. if( bp->outputChannelCount != 0 && bp->hostOutputChannels[0][0].data )
  759. {
  760. for( i=0; i<bp->outputChannelCount; ++i )
  761. {
  762. bp->outputZeroer( hostOutputChannels[i].data,
  763. hostOutputChannels[i].stride,
  764. frameCount );
  765. /* advance dest ptr for next iteration */
  766. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  767. frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  768. }
  769. }
  770. framesProcessed += frameCount;
  771. }
  772. return framesProcessed;
  773. }
  774. /*
  775. AdaptingInputOnlyProcess() is a half duplex input buffer processor. It
  776. converts data from the input buffers into the temporary input buffer,
  777. when the temporary input buffer is full, it calls the streamCallback.
  778. */
  779. static unsigned long AdaptingInputOnlyProcess( PaUtilBufferProcessor *bp,
  780. int *streamCallbackResult,
  781. PaUtilChannelDescriptor *hostInputChannels,
  782. unsigned long framesToProcess )
  783. {
  784. void *userInput, *userOutput;
  785. unsigned char *destBytePtr;
  786. unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
  787. unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
  788. unsigned int i;
  789. unsigned long frameCount;
  790. unsigned long framesToGo = framesToProcess;
  791. unsigned long framesProcessed = 0;
  792. userOutput = 0;
  793. do
  794. {
  795. frameCount = ( bp->framesInTempInputBuffer + framesToGo > bp->framesPerUserBuffer )
  796. ? ( bp->framesPerUserBuffer - bp->framesInTempInputBuffer )
  797. : framesToGo;
  798. /* convert frameCount samples into temp buffer */
  799. if( bp->userInputIsInterleaved )
  800. {
  801. destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
  802. bp->bytesPerUserInputSample * bp->inputChannelCount *
  803. bp->framesInTempInputBuffer;
  804. destSampleStrideSamples = bp->inputChannelCount;
  805. destChannelStrideBytes = bp->bytesPerUserInputSample;
  806. userInput = bp->tempInputBuffer;
  807. }
  808. else /* user input is not interleaved */
  809. {
  810. destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
  811. bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
  812. destSampleStrideSamples = 1;
  813. destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
  814. /* setup non-interleaved ptrs */
  815. for( i=0; i<bp->inputChannelCount; ++i )
  816. {
  817. bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
  818. i * bp->bytesPerUserInputSample * bp->framesPerUserBuffer;
  819. }
  820. userInput = bp->tempInputBufferPtrs;
  821. }
  822. for( i=0; i<bp->inputChannelCount; ++i )
  823. {
  824. bp->inputConverter( destBytePtr, destSampleStrideSamples,
  825. hostInputChannels[i].data,
  826. hostInputChannels[i].stride,
  827. frameCount, &bp->ditherGenerator );
  828. destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
  829. /* advance src ptr for next iteration */
  830. hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
  831. frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
  832. }
  833. bp->framesInTempInputBuffer += frameCount;
  834. if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer )
  835. {
  836. /**
  837. @todo (non-critical optimisation)
  838. The conditional below implements the continue/complete/abort mechanism
  839. simply by continuing on iterating through the input buffer, but not
  840. passing the data to the callback. With care, the outer loop could be
  841. terminated earlier, thus some unneeded conversion cycles would be
  842. saved.
  843. */
  844. if( *streamCallbackResult == paContinue )
  845. {
  846. bp->timeInfo->outputBufferDacTime = 0;
  847. *streamCallbackResult = bp->streamCallback( userInput, userOutput,
  848. bp->framesPerUserBuffer, bp->timeInfo,
  849. bp->callbackStatusFlags, bp->userData );
  850. bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
  851. }
  852. bp->framesInTempInputBuffer = 0;
  853. }
  854. framesProcessed += frameCount;
  855. framesToGo -= frameCount;
  856. }while( framesToGo > 0 );
  857. return framesProcessed;
  858. }
  859. /*
  860. AdaptingOutputOnlyProcess() is a half duplex output buffer processor.
  861. It converts data from the temporary output buffer, to the output buffers,
  862. when the temporary output buffer is empty, it calls the streamCallback.
  863. */
  864. static unsigned long AdaptingOutputOnlyProcess( PaUtilBufferProcessor *bp,
  865. int *streamCallbackResult,
  866. PaUtilChannelDescriptor *hostOutputChannels,
  867. unsigned long framesToProcess )
  868. {
  869. void *userInput, *userOutput;
  870. unsigned char *srcBytePtr;
  871. unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
  872. unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
  873. unsigned int i;
  874. unsigned long frameCount;
  875. unsigned long framesToGo = framesToProcess;
  876. unsigned long framesProcessed = 0;
  877. do
  878. {
  879. if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult == paContinue )
  880. {
  881. userInput = 0;
  882. /* setup userOutput */
  883. if( bp->userOutputIsInterleaved )
  884. {
  885. userOutput = bp->tempOutputBuffer;
  886. }
  887. else /* user output is not interleaved */
  888. {
  889. for( i = 0; i < bp->outputChannelCount; ++i )
  890. {
  891. bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
  892. i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
  893. }
  894. userOutput = bp->tempOutputBufferPtrs;
  895. }
  896. bp->timeInfo->inputBufferAdcTime = 0;
  897. *streamCallbackResult = bp->streamCallback( userInput, userOutput,
  898. bp->framesPerUserBuffer, bp->timeInfo,
  899. bp->callbackStatusFlags, bp->userData );
  900. if( *streamCallbackResult == paAbort )
  901. {
  902. /* if the callback returned paAbort, we disregard its output */
  903. }
  904. else
  905. {
  906. bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
  907. bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
  908. }
  909. }
  910. if( bp->framesInTempOutputBuffer > 0 )
  911. {
  912. /* convert frameCount frames from user buffer to host buffer */
  913. frameCount = PA_MIN_( bp->framesInTempOutputBuffer, framesToGo );
  914. if( bp->userOutputIsInterleaved )
  915. {
  916. srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
  917. bp->bytesPerUserOutputSample * bp->outputChannelCount *
  918. (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
  919. srcSampleStrideSamples = bp->outputChannelCount;
  920. srcChannelStrideBytes = bp->bytesPerUserOutputSample;
  921. }
  922. else /* user output is not interleaved */
  923. {
  924. srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
  925. bp->bytesPerUserOutputSample *
  926. (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
  927. srcSampleStrideSamples = 1;
  928. srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
  929. }
  930. for( i=0; i<bp->outputChannelCount; ++i )
  931. {
  932. bp->outputConverter( hostOutputChannels[i].data,
  933. hostOutputChannels[i].stride,
  934. srcBytePtr, srcSampleStrideSamples,
  935. frameCount, &bp->ditherGenerator );
  936. srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
  937. /* advance dest ptr for next iteration */
  938. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  939. frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  940. }
  941. bp->framesInTempOutputBuffer -= frameCount;
  942. }
  943. else
  944. {
  945. /* no more user data is available because the callback has returned
  946. paComplete or paAbort. Fill the remainder of the host buffer
  947. with zeros.
  948. */
  949. frameCount = framesToGo;
  950. for( i=0; i<bp->outputChannelCount; ++i )
  951. {
  952. bp->outputZeroer( hostOutputChannels[i].data,
  953. hostOutputChannels[i].stride,
  954. frameCount );
  955. /* advance dest ptr for next iteration */
  956. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  957. frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  958. }
  959. }
  960. framesProcessed += frameCount;
  961. framesToGo -= frameCount;
  962. }while( framesToGo > 0 );
  963. return framesProcessed;
  964. }
  965. /* CopyTempOutputBuffersToHostOutputBuffers is called from AdaptingProcess to copy frames from
  966. tempOutputBuffer to hostOutputChannels. This includes data conversion
  967. and interleaving.
  968. */
  969. static void CopyTempOutputBuffersToHostOutputBuffers( PaUtilBufferProcessor *bp)
  970. {
  971. unsigned long maxFramesToCopy;
  972. PaUtilChannelDescriptor *hostOutputChannels;
  973. unsigned int frameCount;
  974. unsigned char *srcBytePtr;
  975. unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
  976. unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
  977. unsigned int i;
  978. /* copy frames from user to host output buffers */
  979. while( bp->framesInTempOutputBuffer > 0 &&
  980. ((bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) > 0) )
  981. {
  982. maxFramesToCopy = bp->framesInTempOutputBuffer;
  983. /* select the output buffer set (1st or 2nd) */
  984. if( bp->hostOutputFrameCount[0] > 0 )
  985. {
  986. hostOutputChannels = bp->hostOutputChannels[0];
  987. frameCount = PA_MIN_( bp->hostOutputFrameCount[0], maxFramesToCopy );
  988. }
  989. else
  990. {
  991. hostOutputChannels = bp->hostOutputChannels[1];
  992. frameCount = PA_MIN_( bp->hostOutputFrameCount[1], maxFramesToCopy );
  993. }
  994. if( bp->userOutputIsInterleaved )
  995. {
  996. srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
  997. bp->bytesPerUserOutputSample * bp->outputChannelCount *
  998. (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
  999. srcSampleStrideSamples = bp->outputChannelCount;
  1000. srcChannelStrideBytes = bp->bytesPerUserOutputSample;
  1001. }
  1002. else /* user output is not interleaved */
  1003. {
  1004. srcBytePtr = ((unsigned char*)bp->tempOutputBuffer) +
  1005. bp->bytesPerUserOutputSample *
  1006. (bp->framesPerUserBuffer - bp->framesInTempOutputBuffer);
  1007. srcSampleStrideSamples = 1;
  1008. srcChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
  1009. }
  1010. for( i=0; i<bp->outputChannelCount; ++i )
  1011. {
  1012. assert( hostOutputChannels[i].data != NULL );
  1013. bp->outputConverter( hostOutputChannels[i].data,
  1014. hostOutputChannels[i].stride,
  1015. srcBytePtr, srcSampleStrideSamples,
  1016. frameCount, &bp->ditherGenerator );
  1017. srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
  1018. /* advance dest ptr for next iteration */
  1019. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  1020. frameCount * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  1021. }
  1022. if( bp->hostOutputFrameCount[0] > 0 )
  1023. bp->hostOutputFrameCount[0] -= frameCount;
  1024. else
  1025. bp->hostOutputFrameCount[1] -= frameCount;
  1026. bp->framesInTempOutputBuffer -= frameCount;
  1027. }
  1028. }
  1029. /*
  1030. AdaptingProcess is a full duplex adapting buffer processor. It converts
  1031. data from the temporary output buffer into the host output buffers, then
  1032. from the host input buffers into the temporary input buffers. Calling the
  1033. streamCallback when necessary.
  1034. When processPartialUserBuffers is 0, all available input data will be
  1035. consumed and all available output space will be filled. When
  1036. processPartialUserBuffers is non-zero, as many full user buffers
  1037. as possible will be processed, but partial buffers will not be consumed.
  1038. */
  1039. static unsigned long AdaptingProcess( PaUtilBufferProcessor *bp,
  1040. int *streamCallbackResult, int processPartialUserBuffers )
  1041. {
  1042. void *userInput, *userOutput;
  1043. unsigned long framesProcessed = 0;
  1044. unsigned long framesAvailable;
  1045. unsigned long endProcessingMinFrameCount;
  1046. unsigned long maxFramesToCopy;
  1047. PaUtilChannelDescriptor *hostInputChannels, *hostOutputChannels;
  1048. unsigned int frameCount;
  1049. unsigned char *destBytePtr;
  1050. unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
  1051. unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
  1052. unsigned int i, j;
  1053. framesAvailable = bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1];/* this is assumed to be the same as the output buffer's frame count */
  1054. if( processPartialUserBuffers )
  1055. endProcessingMinFrameCount = 0;
  1056. else
  1057. endProcessingMinFrameCount = (bp->framesPerUserBuffer - 1);
  1058. /* Fill host output with remaining frames in user output (tempOutputBuffer) */
  1059. CopyTempOutputBuffersToHostOutputBuffers( bp );
  1060. while( framesAvailable > endProcessingMinFrameCount )
  1061. {
  1062. if( bp->framesInTempOutputBuffer == 0 && *streamCallbackResult != paContinue )
  1063. {
  1064. /* the callback will not be called any more, so zero what remains
  1065. of the host output buffers */
  1066. for( i=0; i<2; ++i )
  1067. {
  1068. frameCount = bp->hostOutputFrameCount[i];
  1069. if( frameCount > 0 )
  1070. {
  1071. hostOutputChannels = bp->hostOutputChannels[i];
  1072. for( j=0; j<bp->outputChannelCount; ++j )
  1073. {
  1074. bp->outputZeroer( hostOutputChannels[j].data,
  1075. hostOutputChannels[j].stride,
  1076. frameCount );
  1077. /* advance dest ptr for next iteration */
  1078. hostOutputChannels[j].data = ((unsigned char*)hostOutputChannels[j].data) +
  1079. frameCount * hostOutputChannels[j].stride * bp->bytesPerHostOutputSample;
  1080. }
  1081. bp->hostOutputFrameCount[i] = 0;
  1082. }
  1083. }
  1084. }
  1085. /* copy frames from host to user input buffers */
  1086. while( bp->framesInTempInputBuffer < bp->framesPerUserBuffer &&
  1087. ((bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) > 0) )
  1088. {
  1089. maxFramesToCopy = bp->framesPerUserBuffer - bp->framesInTempInputBuffer;
  1090. /* select the input buffer set (1st or 2nd) */
  1091. if( bp->hostInputFrameCount[0] > 0 )
  1092. {
  1093. hostInputChannels = bp->hostInputChannels[0];
  1094. frameCount = PA_MIN_( bp->hostInputFrameCount[0], maxFramesToCopy );
  1095. }
  1096. else
  1097. {
  1098. hostInputChannels = bp->hostInputChannels[1];
  1099. frameCount = PA_MIN_( bp->hostInputFrameCount[1], maxFramesToCopy );
  1100. }
  1101. /* configure conversion destination pointers */
  1102. if( bp->userInputIsInterleaved )
  1103. {
  1104. destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
  1105. bp->bytesPerUserInputSample * bp->inputChannelCount *
  1106. bp->framesInTempInputBuffer;
  1107. destSampleStrideSamples = bp->inputChannelCount;
  1108. destChannelStrideBytes = bp->bytesPerUserInputSample;
  1109. }
  1110. else /* user input is not interleaved */
  1111. {
  1112. destBytePtr = ((unsigned char*)bp->tempInputBuffer) +
  1113. bp->bytesPerUserInputSample * bp->framesInTempInputBuffer;
  1114. destSampleStrideSamples = 1;
  1115. destChannelStrideBytes = bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
  1116. }
  1117. for( i=0; i<bp->inputChannelCount; ++i )
  1118. {
  1119. bp->inputConverter( destBytePtr, destSampleStrideSamples,
  1120. hostInputChannels[i].data,
  1121. hostInputChannels[i].stride,
  1122. frameCount, &bp->ditherGenerator );
  1123. destBytePtr += destChannelStrideBytes; /* skip to next destination channel */
  1124. /* advance src ptr for next iteration */
  1125. hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
  1126. frameCount * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
  1127. }
  1128. if( bp->hostInputFrameCount[0] > 0 )
  1129. bp->hostInputFrameCount[0] -= frameCount;
  1130. else
  1131. bp->hostInputFrameCount[1] -= frameCount;
  1132. bp->framesInTempInputBuffer += frameCount;
  1133. /* update framesAvailable and framesProcessed based on input consumed
  1134. unless something is very wrong this will also correspond to the
  1135. amount of output generated */
  1136. framesAvailable -= frameCount;
  1137. framesProcessed += frameCount;
  1138. }
  1139. /* call streamCallback */
  1140. if( bp->framesInTempInputBuffer == bp->framesPerUserBuffer &&
  1141. bp->framesInTempOutputBuffer == 0 )
  1142. {
  1143. if( *streamCallbackResult == paContinue )
  1144. {
  1145. /* setup userInput */
  1146. if( bp->userInputIsInterleaved )
  1147. {
  1148. userInput = bp->tempInputBuffer;
  1149. }
  1150. else /* user input is not interleaved */
  1151. {
  1152. for( i = 0; i < bp->inputChannelCount; ++i )
  1153. {
  1154. bp->tempInputBufferPtrs[i] = ((unsigned char*)bp->tempInputBuffer) +
  1155. i * bp->framesPerUserBuffer * bp->bytesPerUserInputSample;
  1156. }
  1157. userInput = bp->tempInputBufferPtrs;
  1158. }
  1159. /* setup userOutput */
  1160. if( bp->userOutputIsInterleaved )
  1161. {
  1162. userOutput = bp->tempOutputBuffer;
  1163. }
  1164. else /* user output is not interleaved */
  1165. {
  1166. for( i = 0; i < bp->outputChannelCount; ++i )
  1167. {
  1168. bp->tempOutputBufferPtrs[i] = ((unsigned char*)bp->tempOutputBuffer) +
  1169. i * bp->framesPerUserBuffer * bp->bytesPerUserOutputSample;
  1170. }
  1171. userOutput = bp->tempOutputBufferPtrs;
  1172. }
  1173. /* call streamCallback */
  1174. *streamCallbackResult = bp->streamCallback( userInput, userOutput,
  1175. bp->framesPerUserBuffer, bp->timeInfo,
  1176. bp->callbackStatusFlags, bp->userData );
  1177. bp->timeInfo->inputBufferAdcTime += bp->framesPerUserBuffer * bp->samplePeriod;
  1178. bp->timeInfo->outputBufferDacTime += bp->framesPerUserBuffer * bp->samplePeriod;
  1179. bp->framesInTempInputBuffer = 0;
  1180. if( *streamCallbackResult == paAbort )
  1181. bp->framesInTempOutputBuffer = 0;
  1182. else
  1183. bp->framesInTempOutputBuffer = bp->framesPerUserBuffer;
  1184. }
  1185. else
  1186. {
  1187. /* paComplete or paAbort has already been called. */
  1188. bp->framesInTempInputBuffer = 0;
  1189. }
  1190. }
  1191. /* copy frames from user (tempOutputBuffer) to host output buffers (hostOutputChannels)
  1192. Means to process the user output provided by the callback. Has to be called after
  1193. each callback. */
  1194. CopyTempOutputBuffersToHostOutputBuffers( bp );
  1195. }
  1196. return framesProcessed;
  1197. }
  1198. unsigned long PaUtil_EndBufferProcessing( PaUtilBufferProcessor* bp, int *streamCallbackResult )
  1199. {
  1200. unsigned long framesToProcess, framesToGo;
  1201. unsigned long framesProcessed = 0;
  1202. if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0
  1203. && bp->hostInputChannels[0][0].data /* input was supplied (see PaUtil_SetNoInput) */
  1204. && bp->hostOutputChannels[0][0].data /* output was supplied (see PaUtil_SetNoOutput) */ )
  1205. {
  1206. assert( (bp->hostInputFrameCount[0] + bp->hostInputFrameCount[1]) ==
  1207. (bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]) );
  1208. }
  1209. assert( *streamCallbackResult == paContinue
  1210. || *streamCallbackResult == paComplete
  1211. || *streamCallbackResult == paAbort ); /* don't forget to pass in a valid callback result value */
  1212. if( bp->useNonAdaptingProcess )
  1213. {
  1214. if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
  1215. {
  1216. /* full duplex non-adapting process, splice buffers if they are
  1217. different lengths */
  1218. framesToGo = bp->hostOutputFrameCount[0] + bp->hostOutputFrameCount[1]; /* relies on assert above for input/output equivalence */
  1219. do{
  1220. unsigned long noInputInputFrameCount;
  1221. unsigned long *hostInputFrameCount;
  1222. PaUtilChannelDescriptor *hostInputChannels;
  1223. unsigned long noOutputOutputFrameCount;
  1224. unsigned long *hostOutputFrameCount;
  1225. PaUtilChannelDescriptor *hostOutputChannels;
  1226. unsigned long framesProcessedThisIteration;
  1227. if( !bp->hostInputChannels[0][0].data )
  1228. {
  1229. /* no input was supplied (see PaUtil_SetNoInput)
  1230. NonAdaptingProcess knows how to deal with this
  1231. */
  1232. noInputInputFrameCount = framesToGo;
  1233. hostInputFrameCount = &noInputInputFrameCount;
  1234. hostInputChannels = 0;
  1235. }
  1236. else if( bp->hostInputFrameCount[0] != 0 )
  1237. {
  1238. hostInputFrameCount = &bp->hostInputFrameCount[0];
  1239. hostInputChannels = bp->hostInputChannels[0];
  1240. }
  1241. else
  1242. {
  1243. hostInputFrameCount = &bp->hostInputFrameCount[1];
  1244. hostInputChannels = bp->hostInputChannels[1];
  1245. }
  1246. if( !bp->hostOutputChannels[0][0].data )
  1247. {
  1248. /* no output was supplied (see PaUtil_SetNoOutput)
  1249. NonAdaptingProcess knows how to deal with this
  1250. */
  1251. noOutputOutputFrameCount = framesToGo;
  1252. hostOutputFrameCount = &noOutputOutputFrameCount;
  1253. hostOutputChannels = 0;
  1254. }
  1255. if( bp->hostOutputFrameCount[0] != 0 )
  1256. {
  1257. hostOutputFrameCount = &bp->hostOutputFrameCount[0];
  1258. hostOutputChannels = bp->hostOutputChannels[0];
  1259. }
  1260. else
  1261. {
  1262. hostOutputFrameCount = &bp->hostOutputFrameCount[1];
  1263. hostOutputChannels = bp->hostOutputChannels[1];
  1264. }
  1265. framesToProcess = PA_MIN_( *hostInputFrameCount,
  1266. *hostOutputFrameCount );
  1267. assert( framesToProcess != 0 );
  1268. framesProcessedThisIteration = NonAdaptingProcess( bp, streamCallbackResult,
  1269. hostInputChannels, hostOutputChannels,
  1270. framesToProcess );
  1271. *hostInputFrameCount -= framesProcessedThisIteration;
  1272. *hostOutputFrameCount -= framesProcessedThisIteration;
  1273. framesProcessed += framesProcessedThisIteration;
  1274. framesToGo -= framesProcessedThisIteration;
  1275. }while( framesToGo > 0 );
  1276. }
  1277. else
  1278. {
  1279. /* half duplex non-adapting process, just process 1st and 2nd buffer */
  1280. /* process first buffer */
  1281. framesToProcess = (bp->inputChannelCount != 0)
  1282. ? bp->hostInputFrameCount[0]
  1283. : bp->hostOutputFrameCount[0];
  1284. framesProcessed = NonAdaptingProcess( bp, streamCallbackResult,
  1285. bp->hostInputChannels[0], bp->hostOutputChannels[0],
  1286. framesToProcess );
  1287. /* process second buffer if provided */
  1288. framesToProcess = (bp->inputChannelCount != 0)
  1289. ? bp->hostInputFrameCount[1]
  1290. : bp->hostOutputFrameCount[1];
  1291. if( framesToProcess > 0 )
  1292. {
  1293. framesProcessed += NonAdaptingProcess( bp, streamCallbackResult,
  1294. bp->hostInputChannels[1], bp->hostOutputChannels[1],
  1295. framesToProcess );
  1296. }
  1297. }
  1298. }
  1299. else /* block adaption necessary*/
  1300. {
  1301. if( bp->inputChannelCount != 0 && bp->outputChannelCount != 0 )
  1302. {
  1303. /* full duplex */
  1304. if( bp->hostBufferSizeMode == paUtilVariableHostBufferSizePartialUsageAllowed )
  1305. {
  1306. framesProcessed = AdaptingProcess( bp, streamCallbackResult,
  1307. 0 /* dont process partial user buffers */ );
  1308. }
  1309. else
  1310. {
  1311. framesProcessed = AdaptingProcess( bp, streamCallbackResult,
  1312. 1 /* process partial user buffers */ );
  1313. }
  1314. }
  1315. else if( bp->inputChannelCount != 0 )
  1316. {
  1317. /* input only */
  1318. framesToProcess = bp->hostInputFrameCount[0];
  1319. framesProcessed = AdaptingInputOnlyProcess( bp, streamCallbackResult,
  1320. bp->hostInputChannels[0], framesToProcess );
  1321. framesToProcess = bp->hostInputFrameCount[1];
  1322. if( framesToProcess > 0 )
  1323. {
  1324. framesProcessed += AdaptingInputOnlyProcess( bp, streamCallbackResult,
  1325. bp->hostInputChannels[1], framesToProcess );
  1326. }
  1327. }
  1328. else
  1329. {
  1330. /* output only */
  1331. framesToProcess = bp->hostOutputFrameCount[0];
  1332. framesProcessed = AdaptingOutputOnlyProcess( bp, streamCallbackResult,
  1333. bp->hostOutputChannels[0], framesToProcess );
  1334. framesToProcess = bp->hostOutputFrameCount[1];
  1335. if( framesToProcess > 0 )
  1336. {
  1337. framesProcessed += AdaptingOutputOnlyProcess( bp, streamCallbackResult,
  1338. bp->hostOutputChannels[1], framesToProcess );
  1339. }
  1340. }
  1341. }
  1342. return framesProcessed;
  1343. }
  1344. int PaUtil_IsBufferProcessorOutputEmpty( PaUtilBufferProcessor* bp )
  1345. {
  1346. return (bp->framesInTempOutputBuffer) ? 0 : 1;
  1347. }
  1348. unsigned long PaUtil_CopyInput( PaUtilBufferProcessor* bp,
  1349. void **buffer, unsigned long frameCount )
  1350. {
  1351. PaUtilChannelDescriptor *hostInputChannels;
  1352. unsigned int framesToCopy;
  1353. unsigned char *destBytePtr;
  1354. void **nonInterleavedDestPtrs;
  1355. unsigned int destSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
  1356. unsigned int destChannelStrideBytes; /* stride from one channel to the next, in bytes */
  1357. unsigned int i;
  1358. hostInputChannels = bp->hostInputChannels[0];
  1359. framesToCopy = PA_MIN_( bp->hostInputFrameCount[0], frameCount );
  1360. if( bp->userInputIsInterleaved )
  1361. {
  1362. destBytePtr = (unsigned char*)*buffer;
  1363. destSampleStrideSamples = bp->inputChannelCount;
  1364. destChannelStrideBytes = bp->bytesPerUserInputSample;
  1365. for( i=0; i<bp->inputChannelCount; ++i )
  1366. {
  1367. bp->inputConverter( destBytePtr, destSampleStrideSamples,
  1368. hostInputChannels[i].data,
  1369. hostInputChannels[i].stride,
  1370. framesToCopy, &bp->ditherGenerator );
  1371. destBytePtr += destChannelStrideBytes; /* skip to next dest channel */
  1372. /* advance source ptr for next iteration */
  1373. hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
  1374. framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
  1375. }
  1376. /* advance callers dest pointer (buffer) */
  1377. *buffer = ((unsigned char *)*buffer) +
  1378. framesToCopy * bp->inputChannelCount * bp->bytesPerUserInputSample;
  1379. }
  1380. else
  1381. {
  1382. /* user input is not interleaved */
  1383. nonInterleavedDestPtrs = (void**)*buffer;
  1384. destSampleStrideSamples = 1;
  1385. for( i=0; i<bp->inputChannelCount; ++i )
  1386. {
  1387. destBytePtr = (unsigned char*)nonInterleavedDestPtrs[i];
  1388. bp->inputConverter( destBytePtr, destSampleStrideSamples,
  1389. hostInputChannels[i].data,
  1390. hostInputChannels[i].stride,
  1391. framesToCopy, &bp->ditherGenerator );
  1392. /* advance callers dest pointer (nonInterleavedDestPtrs[i]) */
  1393. destBytePtr += bp->bytesPerUserInputSample * framesToCopy;
  1394. nonInterleavedDestPtrs[i] = destBytePtr;
  1395. /* advance source ptr for next iteration */
  1396. hostInputChannels[i].data = ((unsigned char*)hostInputChannels[i].data) +
  1397. framesToCopy * hostInputChannels[i].stride * bp->bytesPerHostInputSample;
  1398. }
  1399. }
  1400. bp->hostInputFrameCount[0] -= framesToCopy;
  1401. return framesToCopy;
  1402. }
  1403. unsigned long PaUtil_CopyOutput( PaUtilBufferProcessor* bp,
  1404. const void ** buffer, unsigned long frameCount )
  1405. {
  1406. PaUtilChannelDescriptor *hostOutputChannels;
  1407. unsigned int framesToCopy;
  1408. unsigned char *srcBytePtr;
  1409. void **nonInterleavedSrcPtrs;
  1410. unsigned int srcSampleStrideSamples; /* stride from one sample to the next within a channel, in samples */
  1411. unsigned int srcChannelStrideBytes; /* stride from one channel to the next, in bytes */
  1412. unsigned int i;
  1413. hostOutputChannels = bp->hostOutputChannels[0];
  1414. framesToCopy = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
  1415. if( bp->userOutputIsInterleaved )
  1416. {
  1417. srcBytePtr = (unsigned char*)*buffer;
  1418. srcSampleStrideSamples = bp->outputChannelCount;
  1419. srcChannelStrideBytes = bp->bytesPerUserOutputSample;
  1420. for( i=0; i<bp->outputChannelCount; ++i )
  1421. {
  1422. bp->outputConverter( hostOutputChannels[i].data,
  1423. hostOutputChannels[i].stride,
  1424. srcBytePtr, srcSampleStrideSamples,
  1425. framesToCopy, &bp->ditherGenerator );
  1426. srcBytePtr += srcChannelStrideBytes; /* skip to next source channel */
  1427. /* advance dest ptr for next iteration */
  1428. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  1429. framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  1430. }
  1431. /* advance callers source pointer (buffer) */
  1432. *buffer = ((unsigned char *)*buffer) +
  1433. framesToCopy * bp->outputChannelCount * bp->bytesPerUserOutputSample;
  1434. }
  1435. else
  1436. {
  1437. /* user output is not interleaved */
  1438. nonInterleavedSrcPtrs = (void**)*buffer;
  1439. srcSampleStrideSamples = 1;
  1440. for( i=0; i<bp->outputChannelCount; ++i )
  1441. {
  1442. srcBytePtr = (unsigned char*)nonInterleavedSrcPtrs[i];
  1443. bp->outputConverter( hostOutputChannels[i].data,
  1444. hostOutputChannels[i].stride,
  1445. srcBytePtr, srcSampleStrideSamples,
  1446. framesToCopy, &bp->ditherGenerator );
  1447. /* advance callers source pointer (nonInterleavedSrcPtrs[i]) */
  1448. srcBytePtr += bp->bytesPerUserOutputSample * framesToCopy;
  1449. nonInterleavedSrcPtrs[i] = srcBytePtr;
  1450. /* advance dest ptr for next iteration */
  1451. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  1452. framesToCopy * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  1453. }
  1454. }
  1455. bp->hostOutputFrameCount[0] += framesToCopy;
  1456. return framesToCopy;
  1457. }
  1458. unsigned long PaUtil_ZeroOutput( PaUtilBufferProcessor* bp, unsigned long frameCount )
  1459. {
  1460. PaUtilChannelDescriptor *hostOutputChannels;
  1461. unsigned int framesToZero;
  1462. unsigned int i;
  1463. hostOutputChannels = bp->hostOutputChannels[0];
  1464. framesToZero = PA_MIN_( bp->hostOutputFrameCount[0], frameCount );
  1465. for( i=0; i<bp->outputChannelCount; ++i )
  1466. {
  1467. bp->outputZeroer( hostOutputChannels[i].data,
  1468. hostOutputChannels[i].stride,
  1469. framesToZero );
  1470. /* advance dest ptr for next iteration */
  1471. hostOutputChannels[i].data = ((unsigned char*)hostOutputChannels[i].data) +
  1472. framesToZero * hostOutputChannels[i].stride * bp->bytesPerHostOutputSample;
  1473. }
  1474. bp->hostOutputFrameCount[0] += framesToZero;
  1475. return framesToZero;
  1476. }