pvplay.cpp 52 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440
  1. /*
  2. * Copyright (c) 1983-2023 Richard Dobson and Composers Desktop Project Ltd
  3. * http://www.rwdobson.com
  4. * http://www.composersdesktop.com
  5. * This file is part of the CDP System.
  6. * The CDP System is free software; you can redistribute it
  7. * and/or modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * The CDP System is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * See the GNU Lesser General Public License for more details.
  15. * You should have received a copy of the GNU Lesser General Public
  16. * License along with the CDP System; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. *
  19. */
  20. /* pvplay.cpp
  21. * Play a soundfile or analysis file using PortAudio
  22. *
  23. * Yes yes, I know, this is iffy C++, and there are some gotos to boot. Work in progress...
  24. * and I may yet redo the whole thing in plain C anyway, like paplay.
  25. */
  26. /* OCT 2009 rebuilt with updated pvfileio.c for faster performance on G4 */
  27. /* Feb 2010 rebuilt with new stable portaudio */
  28. /* June 2012 new portaudio, settable audio block size */
  29. /* Jan 2013 changed (as also paplay), at last, to use threaded portaudio ringbuffer code (etc) */
  30. /* Jan 2014: completed pvx support */
  31. #include "pvplay.h"
  32. typedef enum {PLAY_SFILE,PLAY_ANAFILE,PLAY_PVXFILE} PLAYTYPE;
  33. enum {FM_MONO,FM_STEREO,FM_SQUARE,FM_QUAD,FM_PENT,DM_5_0,DM_5_1,FM_HEX,FM_OCT1,FM_OCT2,FM_CUBE,FM_QUADCUBE,FM_NLAYOUTS};
  34. #define NUM_ANALFRAMES (1)
  35. #define RINGBUF_NFRAMES (32768)
  36. #define NUM_WRITES_PER_BUFFER (4)
  37. #ifndef min
  38. #define min(x,y) ((x) < (y) ? (x) : (y))
  39. #endif
  40. #ifdef unix
  41. #include <ctype.h>
  42. int stricmp(const char *a, const char *b);
  43. int strnicmp(const char *a, const char *b, const int length);
  44. #endif
  45. #ifdef WIN32
  46. HANDLE ghEvent;
  47. #endif
  48. int file_playing;
  49. psfdata *g_pdata = NULL;
  50. void playhandler(int sig)
  51. {
  52. if(sig == SIGINT) {
  53. if(file_playing) {
  54. file_playing = 0;
  55. g_pdata->flag = 1;
  56. Pa_Sleep(5);
  57. }
  58. }
  59. }
  60. #ifdef unix
  61. void alarm_wakeup (int i)
  62. {
  63. struct itimerval tout_val;
  64. signal(SIGALRM,alarm_wakeup);
  65. if(file_playing && g_pdata->stream) {
  66. //printf("%.4f secs\r",(float)(g_pdata->frames_played /(double) g_pdata->srate));
  67. g_pdata->lastTime = Pa_GetStreamTime(g_pdata->stream ) - g_pdata->startTime;
  68. printf("%.2f secs\r", g_pdata->lastTime);
  69. fflush(stdout);
  70. }
  71. tout_val.it_interval.tv_sec = 0;
  72. tout_val.it_interval.tv_usec = 0;
  73. tout_val.it_value.tv_sec = 0;
  74. tout_val.it_value.tv_usec = 200000;
  75. setitimer(ITIMER_REAL, &tout_val,0);
  76. }
  77. #endif
  78. void finishedCallback(void *userData)
  79. {
  80. psfdata *pdata = (psfdata*) userData;
  81. //printf("stream finished!\n");
  82. pdata->finished = 1;
  83. file_playing = 0;
  84. }
  85. #ifdef WIN32
  86. VOID CALLBACK TimerCallback(PVOID lpParam, BOOLEAN TimerOrWaitFired)
  87. {
  88. psfdata *pdata = (psfdata*) lpParam;
  89. if(file_playing && pdata->stream) {
  90. //printf("%.4f secs\r",(float)(g_pdata->frames_played /(double) g_pdata->srate));
  91. pdata->lastTime = Pa_GetStreamTime(pdata->stream ) - pdata->startTime;
  92. printf("%.2f secs\r", pdata->lastTime);
  93. fflush(stdout);
  94. }
  95. SetEvent(ghEvent);
  96. }
  97. #endif
  98. /* This routine will be called by the PortAudio engine when audio is needed.
  99. ** It may called at interrupt level on some machines so don't do anything
  100. ** that could mess up the system like calling malloc() or free().
  101. */
  102. #ifdef NOTDEF
  103. // need this?
  104. static void porttimeCallback(PtTimestamp timestamp, void *userData)
  105. {
  106. PtTimestamp curtime = Pt_Time();
  107. double timesecs = (double) curtime * 0.001;
  108. printf("%.3lf\r",timesecs);
  109. }
  110. #endif
  111. /* Start up a new thread for given function */
  112. static PaError startThread( psfdata* pdata, threadfunc fn )
  113. {
  114. pdata->flag = 1;
  115. #ifdef WIN32
  116. pdata->hThread = (void*)_beginthreadex(NULL, 0, fn, pdata, 0, NULL);
  117. if (pdata->hThread == NULL)
  118. return paUnanticipatedHostError;
  119. /* Wait for thread to startup */
  120. while (pdata->flag) {
  121. Pa_Sleep(10);
  122. }
  123. /* Set file thread to a little higher priority than normal */
  124. SetThreadPriority(pdata->hThread, THREAD_PRIORITY_ABOVE_NORMAL);
  125. //#endif
  126. #else
  127. #if defined(__APPLE__) || defined(__GNUC__)
  128. if(pthread_create(&pdata->hThread,NULL,/*(void*)*/ fn,pdata))
  129. return -1;
  130. /* Wait for thread to startup */
  131. while (pdata->flag) {
  132. Pa_Sleep(10);
  133. }
  134. #endif
  135. #endif
  136. return paNoError;
  137. }
  138. #if 0
  139. static int stopThread( psfdata* pdata )
  140. {
  141. // just called when all data played; must be called before StopStream
  142. // pdata->flag = 1;
  143. /* Wait for thread to stop */
  144. while (pdata->flag==0) {
  145. Pa_Sleep(10);
  146. }
  147. #ifdef WIN32
  148. CloseHandle(pdata->hThread);
  149. pdata->hThread = 0;
  150. #else
  151. #if defined(__APPLE__) || defined(__GNUC__)
  152. pthread_cancel(pdata->hThread);
  153. #endif
  154. #endif
  155. return paNoError;
  156. }
  157. #endif
  158. static int paplayCallback(const void *inputBuffer, void *outputBuffer,
  159. unsigned long framesPerBuffer,
  160. const PaStreamCallbackTimeInfo* timeInfo,
  161. PaStreamCallbackFlags statusFlags,
  162. void *userData )
  163. {
  164. psfdata *data = (psfdata *)userData;
  165. ring_buffer_size_t sampsAvailable = PaUtil_GetRingBufferReadAvailable(&data->ringbuf) * data->outchans;
  166. ring_buffer_size_t sampsToPlay = min(sampsAvailable, (ring_buffer_size_t)(framesPerBuffer * data->outchans));
  167. float *out = (float*) outputBuffer;
  168. int framesToPlay = sampsToPlay / data->outchans;
  169. int played;
  170. // if framestoplay < framesPerBuffer, need to clean up the remainder
  171. memset(out,0,framesPerBuffer * data->outchans * sizeof(float));
  172. played = PaUtil_ReadRingBuffer(&data->ringbuf, out, framesToPlay);
  173. data->frames_played += played;
  174. if(data->flag) {
  175. //printf("callback - complete\n");
  176. return paComplete;
  177. }
  178. return paContinue;
  179. }
  180. static int MemCallback(const void *inputBuffer, void *outputBuffer,
  181. unsigned long framesPerBuffer,
  182. const PaStreamCallbackTimeInfo* timeInfo,
  183. PaStreamCallbackFlags statusFlags,
  184. void *userData )
  185. {
  186. psfdata *pdata = (psfdata *)userData;
  187. float *out = (float*) outputBuffer;
  188. unsigned long inSamps,outSamps, inSampPos;
  189. unsigned long i;
  190. unsigned long framesToPlay = framesPerBuffer;
  191. // if framesToPlay < framesPerBuffer, need to clean up the remainder
  192. memset(out,0,framesPerBuffer * pdata->outchans * sizeof(float));
  193. inSamps = pdata->memFramelength * pdata->inchans;
  194. outSamps = framesPerBuffer * pdata->inchans;
  195. inSampPos = pdata->memFramePos * pdata->inchans;
  196. if(pdata->play_looped){
  197. for(i=0;i < outSamps; i++){
  198. pdata->inbuf[i] = pdata->membuf[inSampPos++] * pdata->gain;
  199. if(inSampPos == inSamps)
  200. inSampPos = 0;
  201. }
  202. }
  203. else {
  204. for(i=0;i < outSamps; i++){
  205. pdata->inbuf[i] = pdata->membuf[inSampPos++] * pdata->gain;
  206. if(inSampPos == inSamps)
  207. break;
  208. }
  209. framesToPlay = i / pdata->inchans;
  210. for(; i < outSamps;i++){
  211. pdata->inbuf[i] = 0.0;
  212. }
  213. }
  214. // write to output
  215. // everything now in inbuf
  216. if(pdata->do_decode) {
  217. ABFSAMPLE abfsamp;
  218. unsigned long j;
  219. for(j=0; j < framesToPlay; j++){
  220. pdata->copyfunc(&abfsamp,pdata->inbuf + (j * pdata->inchans));
  221. pdata->decodefunc(&abfsamp,out + (j * pdata->outchans), 1);
  222. }
  223. }
  224. else { // inchans = outchans
  225. memcpy(out,pdata->inbuf,framesToPlay * sizeof(float) * pdata->inchans);
  226. }
  227. pdata->memFramePos = inSampPos / pdata->inchans;
  228. pdata->frames_played += framesToPlay;
  229. if(framesToPlay < framesPerBuffer)
  230. pdata->flag = 1; // end of stream
  231. if(pdata->flag) {
  232. return paComplete;
  233. }
  234. return paContinue;
  235. }
  236. static unsigned NextPowerOf2(unsigned val)
  237. {
  238. val--;
  239. val = (val >> 1) | val;
  240. val = (val >> 2) | val;
  241. val = (val >> 4) | val;
  242. val = (val >> 8) | val;
  243. val = (val >> 16) | val;
  244. return ++val;
  245. }
  246. #define N_BFORMATS (10)
  247. // static const int bformats[N_BFORMATS] = {2,3,4,5,6,7,8,9,11,16};
  248. // static const int layout_chans[] = {1,2,4,4,5,5,6,6,8,8,8,8};
  249. /* no M flag here */
  250. enum {FLAG_B = 0, FLAG_BM, FLAG_D, FLAG_G, FLAG_H, FLAG_I, FLAG_L, FLAG_NFLAGS};
  251. void usage(void){
  252. #ifdef WIN32
  253. printf("usage:\n pvplay [-BN][-dN][-gN]-hN][-i][-l][-b[N]][-u][-x] infile [from] [to] \n"
  254. #else
  255. printf("usage:\n pvplay [-BN][-dN][-gN]-hN][-i][-l][-b[N]][-u] infile [from] [to]\n"
  256. #endif
  257. " -dN : use output Device N.\n"
  258. " -gN : apply gain factor N to input.\n"
  259. " -BN : set memory buffer size to N frames (default: %d).\n"
  260. " N must be a power of 2 (e.g 4096, 8192, 16384 etc).\n"
  261. " -hN : set hardware blocksize to N frames (32 < N <= BN/4), default is set internally.\n"
  262. " (N recommended to be a power of two size).\n"
  263. " : NB: for sample rates > 48KHz, buffer sizes are doubled internally.\n"
  264. " -i : play immediately (do not wait for keypress).\n"
  265. " -l : loop file continuously, from start-time to end-time.\n"
  266. " -u : suppress elapsed time updates\n"
  267. #ifdef WIN32
  268. " -x : Apply WAVE_EX infile channel mask to DS audio stream\n"
  269. " (ignored if -m or -b used)\n"
  270. #endif
  271. " from : set start time (secs) for playback and looping. Default: 0.\n"
  272. " to : set end time (secs) for playback and looping. Default: EOF.\n"
  273. " -b[N]: apply 1st-order B-Format decoding to standard soundfile.\n"
  274. " (file must have at least 3 channels)\n"
  275. " B-Format files (.amb) will be decoded automatically.\n"
  276. " N sets speaker layout to one of the following:\n"
  277. " 1 : * mono (= W signal only)\n"
  278. " 2 : * stereo (quasi mid/side, = W +- Y)\n"
  279. " 3 : square\n"
  280. " 4 : * quad FL,FR,RL,RR order (default)\n"
  281. " 5 : pentagon\n"
  282. " 6 : * 5.0 surround (WAVEX order)\n"
  283. " 7 : * 5.1 surround (WAVEX order, silent LFE)\n"
  284. " 8 : hexagon\n"
  285. " 9 : octagon 1 (front pair, 45deg)\n"
  286. " 10 : octagon 2 (front centre speaker)\n"
  287. " 11 : cube (as 3, low-high interleaved. Csound-compatible.)\n"
  288. " 12 : * cube (as 4, low quad followed by high quad).\n"
  289. " Default decode layout is 4 (quad).\n"
  290. " NB: no decoding is performed if -m flag used.\n"
  291. " pvplay reads PEAK chunk if present to rescale over-range floatsam files.\n\n"
  292. ,RINGBUF_NFRAMES);
  293. }
  294. /*******************************************************************/
  295. int main(int argc,char **argv)
  296. {
  297. PaStreamParameters outputParameters;
  298. #ifdef WIN32
  299. /* portaudio sets default channel masks we can't use; we must do all this to set default mask = 0! */
  300. PaWinDirectSoundStreamInfo directSoundStreamInfo;
  301. // PaWinMmeStreamInfo winmmeStreamInfo;
  302. #endif
  303. PaDeviceInfo *devinfo = NULL;
  304. PaStream *stream = NULL;
  305. PaStreamCallback *playcallback = paplayCallback;
  306. PaError err = paNoError;
  307. SFPROPS props;
  308. psfdata sfdata;
  309. CHPEAK *fpeaks = NULL;
  310. //ABFSAMPLE *abf_frame = NULL;
  311. int res,inorder = 1;
  312. time_t in_peaktime = 0;
  313. int waitkey = 1;
  314. //int play_looped = 0;
  315. double fromdur = 0.0;
  316. double totime = 0.0;
  317. int from_frame = 0, to_frame = 0;
  318. unsigned int i=0;
  319. long anal_nframes;
  320. PaDeviceIndex device;
  321. //long framesread;
  322. long filesize;
  323. //long framesize = 0;
  324. unsigned long ringframelen = RINGBUF_NFRAMES; // length of ring buffer in m/c frames
  325. unsigned long frames_per_buffer = 0; // default is to let portaudio decide
  326. unsigned long nFramesToPlay = 0;
  327. double gain = 1.0;
  328. unsigned int inchans = 0,outchans = 0; // may be different if decoding B-Format
  329. int layout = 4; // default, quad decode */
  330. fmhcopyfunc copyfunc = NULL;
  331. fmhdecodefunc decodefunc = NULL;
  332. /* chorder facility not included in pvplay - use paplay! */
  333. unsigned int flags[FLAG_NFLAGS] = {0};
  334. #ifdef WIN32
  335. int speakermask = 0;
  336. int do_speakermask = 0;
  337. #endif
  338. int do_updatemessages = 1;
  339. #ifdef unix
  340. struct itimerval tout_val;
  341. tout_val.it_interval.tv_sec = 0;
  342. tout_val.it_interval.tv_usec = 0;
  343. tout_val.it_value.tv_sec = 0;
  344. tout_val.it_value.tv_usec = 200000;
  345. #endif
  346. char* ext = 0;
  347. PVOCDATA *p_pvdata = NULL;
  348. WAVEFORMATEX *p_wfx = NULL;
  349. //int pvfile = -1;
  350. //pvoc_frametype inframetype;
  351. pvoc_windowtype wtype;
  352. //double oneovrsr;
  353. int anal_buflen,overlap,winlen;
  354. // for sfiles only, for now
  355. //int framesize_factor = 0;
  356. //phasevocoder *pv = NULL, *pv_r = NULL;
  357. PLAYTYPE playtype = PLAY_SFILE;
  358. #ifdef WIN32
  359. HANDLE hTimerQueue;
  360. ghEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  361. if(ghEvent==NULL){
  362. printf("Failed to start internal timer (1).\n");
  363. return 1;
  364. }
  365. hTimerQueue = CreateTimerQueue();
  366. if(hTimerQueue == NULL){
  367. printf("Failed to start internal timer (2).\n");
  368. return 1;
  369. }
  370. #endif
  371. /* CDP version number; now set for release 7 */
  372. if(argc==2 && (stricmp(argv[1],"--version")==0)){
  373. printf("7.1.0\n");
  374. return 0;
  375. }
  376. signal(SIGINT,playhandler);
  377. //sf_frames = FRAMESIZE; // need this for pvoc playback reporting
  378. sfdata.inbuf = NULL;
  379. sfdata.membuf = NULL;
  380. sfdata.memFramelength = 0;
  381. sfdata.memFramePos = 0;
  382. sfdata.current_frame = 0;
  383. sfdata.ringbufData = NULL;
  384. sfdata.outbuf_l = NULL;
  385. sfdata.outbuf_r = NULL;
  386. sfdata.pvfile = -1;
  387. printf("PvPlay: play multi-channel PCM and analysis files (.ana, .pvx). V7.0.0 RWD,CDP 2014\n");
  388. file_playing = 0;
  389. err = Pa_Initialize();
  390. if( err != paNoError ) {
  391. fprintf(stderr,"Portaudio startup error.\n");
  392. return 1;
  393. }
  394. device = Pa_GetDefaultOutputDevice();
  395. if(device < 0){
  396. fprintf(stderr,"Cannot find any audio output device\n");
  397. return 1;
  398. }
  399. if(argc < 2){
  400. usage();
  401. show_devices();
  402. Pa_Terminate();
  403. return 1;
  404. }
  405. while(argv[1][0]=='-'){
  406. unsigned long userbuflen;
  407. switch(argv[1][1]){
  408. case('b'):
  409. if(flags[FLAG_B]){
  410. printf("error: multiple -b flags\n");
  411. Pa_Terminate();
  412. return 1;
  413. }
  414. if(argv[1][2] != '\0'){
  415. layout = atoi(&argv[1][2]);
  416. if(layout < 1 || layout > 12){
  417. fprintf(stderr,"value for -b flag out of range.\n");
  418. Pa_Terminate();
  419. return 1;
  420. }
  421. }
  422. flags[FLAG_B] = 1;
  423. break;
  424. case('d'):
  425. if(flags[FLAG_D]){
  426. printf("error: multiple -d flags\n");
  427. Pa_Terminate();
  428. return 1;
  429. }
  430. if(argv[1][2]=='\0'){
  431. printf("-d flag requires parameter\n");
  432. Pa_Terminate();
  433. return 1;
  434. }
  435. device = atoi(&(argv[1][2]));
  436. flags[FLAG_D] = 1;
  437. break;
  438. case('g'):
  439. if(flags[FLAG_G]){
  440. printf("error: multiple -g flags\n");
  441. Pa_Terminate();
  442. return 1;
  443. }
  444. if(argv[1][2]=='\0'){
  445. printf("-g flag requires parameter\n");
  446. Pa_Terminate();
  447. return 1;
  448. }
  449. gain = atof(&(argv[1][2]));
  450. if(gain <= 0.0){
  451. fprintf(stderr,"gain value must be positive.\n");
  452. Pa_Terminate();
  453. return 1;
  454. }
  455. flags[FLAG_G] = 1;
  456. break;
  457. case 'h':
  458. if(flags[FLAG_H]){
  459. printf("error: multiple -h flags\n");
  460. Pa_Terminate();
  461. return 1;
  462. }
  463. if(argv[1][2]=='\0'){
  464. printf("-h flag requires parameter\n");
  465. Pa_Terminate();
  466. return 1;
  467. }
  468. frames_per_buffer = atoi(&(argv[1][2]));
  469. if((frames_per_buffer > 0) && (frames_per_buffer < 32)){
  470. printf("-h value too small: must be at least 32.\n");
  471. Pa_Terminate();
  472. return 1;
  473. }
  474. flags[FLAG_H] = 1;
  475. break;
  476. case('i'):
  477. if(flags[FLAG_I]){
  478. printf("error: multiple -i flags\n");
  479. Pa_Terminate();
  480. return 1;
  481. }
  482. flags[FLAG_I] = 1;
  483. waitkey = 0;
  484. break;
  485. case ('l'):
  486. flags[FLAG_L] = 1;
  487. break;
  488. case 'u':
  489. do_updatemessages = 0;
  490. break;
  491. #ifdef WIN32
  492. case 'x':
  493. do_speakermask = 1;
  494. break;
  495. #endif
  496. case 'B':
  497. if(flags[FLAG_BM]){
  498. printf("error: multiple -B flags\n");
  499. Pa_Terminate();
  500. return 1;
  501. }
  502. if(argv[1][2]=='\0'){
  503. printf("-B flag requires parameter\n");
  504. Pa_Terminate();
  505. return 1;
  506. }
  507. ringframelen = atoi(&(argv[1][2]));
  508. if(ringframelen <= 1024){
  509. printf("-B: framesize value must be >=1024!n");
  510. Pa_Terminate();
  511. return 1;
  512. }
  513. userbuflen = NextPowerOf2(ringframelen);
  514. if(userbuflen != ringframelen){
  515. printf("-B: framesize value must be power of 2 size\n");
  516. Pa_Terminate();
  517. return 1;
  518. }
  519. flags[FLAG_BM] = 1;
  520. break;
  521. default:
  522. printf("unrecognised flag option\n");
  523. Pa_Terminate();
  524. return 1;
  525. }
  526. argv++; argc--;
  527. }
  528. if(frames_per_buffer > ringframelen/4){
  529. printf(" hardware (-h) framesize %lu too large for file buffer (-B) size %lu\n",
  530. frames_per_buffer,ringframelen);
  531. Pa_Terminate();
  532. return 1;
  533. }
  534. if(argc < 2 || argc > 4){
  535. usage();
  536. show_devices();
  537. Pa_Terminate();
  538. return 1;
  539. }
  540. if(argc>=3){
  541. fromdur = atof(argv[2]);
  542. if(fromdur < 0.0){
  543. printf("Error: start position must be positive\n");
  544. Pa_Terminate();
  545. return 1;
  546. }
  547. }
  548. if(argc==4){
  549. totime = atof(argv[3]);
  550. if(totime <= fromdur){
  551. printf("Error: end time must be after from time\n");
  552. Pa_Terminate();
  553. return 1;
  554. }
  555. }
  556. if(!init_pvsys()){
  557. puts("\nUnable to start pvsys.");
  558. return 1;
  559. }
  560. if(sflinit("pvplay")){
  561. puts("\nUnable to start sfsys.");
  562. return 1;
  563. }
  564. /* get pvocex filetype from extension */
  565. ext = strrchr(argv[1],'.');
  566. if(ext && stricmp(ext,".pvx")==0){
  567. p_pvdata = new PVOCDATA;
  568. if(p_pvdata==NULL){
  569. puts("\nNo Memory!");
  570. return 1;
  571. }
  572. p_wfx = new WAVEFORMATEX;
  573. if(p_wfx==NULL){
  574. puts("\nNo Memory!");
  575. return 1;
  576. }
  577. sfdata.pvfile = pvoc_openfile(argv[1],p_pvdata,p_wfx);
  578. if(sfdata.pvfile< 0){
  579. fprintf(stderr,"\npvplay: unable to open pvx file: %s",pvoc_errorstr());
  580. return 1;
  581. }
  582. props.srate = p_wfx->nSamplesPerSec;
  583. if(props.srate <=0){
  584. fprintf(stderr,"\nbad srate found: corrupted file?\n");
  585. return 1;
  586. }
  587. sfdata.srate = props.srate;
  588. /*stick to mono/stereo for now */
  589. if(p_wfx->nChannels > 2){
  590. fprintf(stderr,"\nSorry: can only read mono or stereo pvx files.");
  591. return 1;
  592. }
  593. inchans = p_wfx->nChannels;
  594. props.chans = inchans;
  595. outchans = inchans;
  596. /* calc size in m/c analysis frames of this analysis file */
  597. filesize = pvoc_framecount(sfdata.pvfile) / inchans;
  598. double dur = (double) filesize / (double)(p_pvdata->fAnalysisRate);
  599. filesize = (long)(dur * props.srate);
  600. sfdata.anal_framesize = (p_pvdata->nAnalysisBins/*- 1*/) * 2;
  601. sfdata.fftsize = sfdata.anal_framesize-2;
  602. winlen = p_pvdata->dwWinlen;
  603. overlap = p_pvdata->dwOverlap;
  604. sfdata.inframetype = (pvoc_frametype) p_pvdata->wAnalFormat;
  605. // oneovrsr = 1.0 / (double) props.srate;
  606. wtype = (pvoc_windowtype) p_pvdata->wWindowType;
  607. /* adjust buffer size to multiple of overlap */
  608. anal_buflen = sfdata.anal_framesize * NUM_ANALFRAMES;
  609. anal_buflen = (anal_buflen / overlap) * overlap;
  610. /* mono */
  611. sfdata.analframe1 = new float[sfdata.anal_framesize];
  612. memset(sfdata.analframe1,0,sfdata.anal_framesize * sizeof(float));
  613. sfdata.pv_l = new phasevocoder();
  614. if(!sfdata.pv_l->init(props.srate,sfdata.anal_framesize-2,winlen,overlap,1.0,PVOC_S_NONE,wtype,PVPP_STREAMING)){
  615. fprintf(stderr,"\nUnable to initialize pvoc Channel 1.");
  616. //delete sfdata.pv_l;
  617. //delete sfdata.analframe1;
  618. return 1;
  619. }
  620. if(inchans==2){
  621. /* need two intermediate buffers, to be interleaved into sampbuf */
  622. sfdata.analframe2 = new float[sfdata.anal_framesize];
  623. memset(sfdata.analframe2,0,sfdata.anal_framesize * sizeof(float));
  624. sfdata.pv_r = new phasevocoder();
  625. if(!sfdata.pv_r->init(props.srate,sfdata.anal_framesize-2,winlen,overlap,1.0,PVOC_S_NONE,wtype,PVPP_STREAMING)){
  626. fprintf(stderr,"\nUnable to initialize pvoc Channel 2.");
  627. //delete sfdata.pv_l;
  628. //delete sfdata.pv_r;
  629. //delete sfdata.outbuf_l;
  630. //delete sfdata.outbuf_r;
  631. //delete sfdata.analframe1;
  632. //delete sfdata.analframe2;
  633. return 1;
  634. }
  635. }
  636. to_frame = (pvoc_framecount(sfdata.pvfile) / inchans) - 1;
  637. if(fromdur > 0.0){
  638. //printf("SORRY: from parameter ignored: not yet supported for pvx files\n");
  639. from_frame = (long)(fromdur * (props.srate/overlap));
  640. if(from_frame >= to_frame){
  641. printf("Error: start frame %d is beyond end of file\n", from_frame);
  642. goto error;
  643. }
  644. if(pvoc_seek_mcframe(sfdata.pvfile,from_frame,SEEK_SET)){
  645. printf("Error: from: failed to seek to frame %d\n",from_frame);
  646. goto error;
  647. }
  648. }
  649. if(totime > 0.0){
  650. long targetframe = (long)(totime * (props.srate/overlap));
  651. if(targetframe >= to_frame){
  652. printf("Error: end time is beyond end of file\n");
  653. goto error;
  654. }
  655. if(targetframe <= from_frame){
  656. printf("Start time must be less than end time.\n");
  657. goto error;
  658. }
  659. to_frame = targetframe;
  660. if(to_frame - from_frame < 1){
  661. to_frame = from_frame+1; // maybe we can in fact freeze on a single frame!
  662. // but we will not use in-memory system in this case
  663. }
  664. nFramesToPlay = to_frame - from_frame;
  665. printf("Playing %d analysis frames\n",(int) nFramesToPlay);
  666. }
  667. playtype = PLAY_PVXFILE;
  668. }
  669. /* soundfile or anafile*/
  670. else {
  671. /* allow auto rescaling of overrange floats via PEAK chunk */
  672. sfdata.ifd = sndopenEx(argv[1],1,CDP_OPEN_RDONLY);
  673. if(sfdata.ifd < 0) {
  674. printf("unable to open soundfile %s : %s\n",argv[1],sferrstr());
  675. return 1;
  676. }
  677. if(!snd_headread(sfdata.ifd,&props)) {
  678. fprintf(stderr,"\nError reading sfile header");
  679. fprintf(stderr,"\n%s",props_errstr);
  680. return 1;
  681. }
  682. inchans = props.chans;
  683. filesize = sndsizeEx(sfdata.ifd); // get size in frames
  684. if(filesize == 0){
  685. printf("File is empty!\n");
  686. return 1;
  687. }
  688. bool adjusted = false; // in case we have to increase ringframelen for huge FFT size
  689. switch(props.type){
  690. case wt_analysis:
  691. sfdata.anal_framesize = props.chans;
  692. outchans = inchans = props.chans = 1;
  693. props.srate = props.origrate;
  694. anal_nframes = filesize / sfdata.anal_framesize ; // * chans ?
  695. if(anal_nframes <= 1){
  696. fprintf(stderr,"Bad analysis file - not enough frames\n");
  697. return 1;
  698. }
  699. sfdata.analframe1 = new float[sfdata.anal_framesize];
  700. winlen = props.winlen;
  701. /* TODO: match ringbuf length to multiple of FFT size */
  702. sfdata.fftsize = sfdata.anal_framesize - 2;
  703. sfdata.pv_l = new phasevocoder;
  704. if(!sfdata.pv_l->init(props.origrate,sfdata.anal_framesize-2,props.winlen,props.decfac,1.0,
  705. PVOC_S_NONE,PVOC_HAMMING,PVPP_STREAMING)){
  706. fprintf(stderr,"Error: unable to initialize pvoc engine.\n");
  707. return 1;
  708. }
  709. overlap = sfdata.pv_l->anal_overlap();
  710. //anal_buflen = /*FRAMESIZE * NUM_ANALFRAMES*/ anal_framesize; // always mono
  711. //anal_buflen = (anal_buflen / overlap) * overlap;
  712. // buflen = anal_buflen;
  713. from_frame = (long)(fromdur * props.arate);
  714. if(from_frame >= anal_nframes){
  715. printf("Error: start is beyond end of file\n");
  716. goto error;
  717. }
  718. to_frame = anal_nframes -1;
  719. if(totime > 0.0){
  720. to_frame = (long)(totime * props.arate + 0.5);
  721. if(to_frame >= anal_nframes){
  722. printf("Error: end time is beyond end of file\n");
  723. goto error;
  724. }
  725. if(to_frame <= from_frame){
  726. printf("Start time must be less than end time.\n");
  727. goto error;
  728. }
  729. if(to_frame - from_frame < 1){
  730. to_frame = from_frame +1; // maybe we can in fact freeze on a single frame!
  731. // but we will not use in-memory system in this case
  732. }
  733. nFramesToPlay = to_frame - from_frame;
  734. printf("Playing %d analysis frames\n",(int) nFramesToPlay);
  735. }
  736. if(from_frame > 0){
  737. if(sndseekEx(sfdata.ifd,from_frame * sfdata.anal_framesize,SEEK_SET) < 0) {
  738. printf("Error setting start position to frame %d\n", from_frame);
  739. printf("%s", sferrstr());
  740. goto error;
  741. }
  742. sfdata.current_frame = from_frame;
  743. }
  744. // ensure ring buffer is large enough even for huge FFT lengths!
  745. adjusted = false;
  746. while(ringframelen < (unsigned long)(sfdata.fftsize * 4)) {
  747. ringframelen <<= 1;
  748. adjusted = true;
  749. }
  750. //printf("from = %d, to = %d\n",from_frame, to_frame);
  751. playtype = PLAY_ANAFILE;
  752. printf("Opened %s: %ld frames, %d channels\n",argv[1],anal_nframes,props.chans);
  753. if(adjusted)
  754. printf("FFT frame size = %d, expanding buffer to suit...\n", sfdata.fftsize);
  755. break;
  756. case wt_wave:
  757. playtype = PLAY_SFILE;
  758. printf("Opened %s: %ld frames, %d channels\n",argv[1],filesize,props.chans);
  759. //framesize_factor = (long) (48000/ props.srate);
  760. //framesize_factor += 1;
  761. filesize /= inchans;
  762. #ifdef WIN32
  763. if(props.format == WAVE_EX){
  764. if(do_speakermask){
  765. int mask;
  766. if(flags[FLAG_B]){
  767. printf("-x flag ignored if -B used\n");
  768. }
  769. else {
  770. mask = sndgetchanmask(sfdata.ifd);
  771. if(mask < 0){
  772. printf("Could not read speaker mask. Using 0\n");
  773. }
  774. else
  775. speakermask = mask;
  776. }
  777. }
  778. }
  779. #endif
  780. from_frame = (long)(fromdur * props.srate);
  781. if(from_frame >= filesize){
  782. printf("Error: start is beyond end of file\n");
  783. goto error;
  784. }
  785. nFramesToPlay = filesize - from_frame;
  786. to_frame = filesize -1;
  787. if(totime > 0.0){
  788. to_frame = (long)(totime * props.srate);
  789. if(to_frame >= filesize){
  790. printf("Error: end time is beyond end of file\n");
  791. goto error;
  792. }
  793. //printf("fromframe = %d, toframe = %d\n",(int)from_frame,(int) to_frame);
  794. if(to_frame <= from_frame){
  795. printf("End time must be later than from time\n");
  796. goto error;
  797. }
  798. nFramesToPlay = to_frame - from_frame;
  799. printf("Playing %d frames\n",(int) nFramesToPlay);
  800. }
  801. if(from_frame > 0){
  802. if(sndseekEx(sfdata.ifd,from_frame * inchans,SEEK_SET) < 0) {
  803. printf("Error setting start position\n");
  804. goto error;
  805. }
  806. sfdata.current_frame = from_frame;
  807. }
  808. outchans = inchans = props.chans;
  809. if(props.chformat==MC_BFMT){
  810. flags[FLAG_B] = 1;
  811. if(inchans > 4) {
  812. inorder = 2;
  813. printf("%u-channel input: performing 2nd-order decode.\n",inchans);
  814. }
  815. switch(inchans){
  816. case 3:
  817. copyfunc = fmhcopy_3;
  818. break;
  819. case 4:
  820. copyfunc = fmhcopy_4;
  821. break;
  822. case 5:
  823. copyfunc = fmhcopy_5;
  824. break;
  825. case 6:
  826. copyfunc = fmhcopy_6;
  827. break;
  828. case 9:
  829. copyfunc = fmhcopy_9;
  830. break;
  831. case 11:
  832. copyfunc = fmhcopy_11;
  833. break;
  834. case 16:
  835. copyfunc = fmhcopy_16;
  836. break;
  837. default:
  838. fprintf(stderr,"Unsupported channel count (%u) for B-format file.\n",inchans);
  839. return 1;
  840. }
  841. switch(layout-1) {
  842. case FM_MONO:
  843. printf("Decoding to Mono\n");
  844. decodefunc = fm_i1_mono;
  845. outchans = 1;
  846. break;
  847. case FM_STEREO:
  848. printf("Decoding to Stereo\n");
  849. decodefunc = fm_i1_stereo;
  850. outchans = 2;
  851. break;
  852. case FM_SQUARE:
  853. printf("Decoding to Square\n");
  854. if(inorder == 1)
  855. decodefunc = fm_i1_square;
  856. else
  857. decodefunc = fm_i2_square;
  858. outchans = 4;
  859. break;
  860. case FM_PENT:
  861. printf("Decoding to pentagon\n");
  862. if(inorder==1)
  863. decodefunc = fm_i1_pent;
  864. else
  865. decodefunc = fm_i2_pent;
  866. outchans = 5;
  867. break;
  868. case DM_5_0:
  869. printf("Decoding to 5.0 surround (David Moore)\n");
  870. if(inorder==1)
  871. decodefunc = dm_i1_surr;
  872. else
  873. decodefunc = dm_i2_surr;
  874. outchans = 5;
  875. break;
  876. case DM_5_1:
  877. printf("Decoding to 5.1 surround (David Moore)\n");
  878. if(inorder==1)
  879. decodefunc = dm_i1_surr6;
  880. else
  881. decodefunc = dm_i2_surr6;
  882. outchans = 6;
  883. break;
  884. case FM_HEX:
  885. printf("Decoding to Hexagon\n");
  886. if(inorder==1)
  887. decodefunc = fm_i1_hex;
  888. else
  889. decodefunc = fm_i2_hex;
  890. outchans = 6;
  891. break;
  892. case FM_OCT1:
  893. printf("Decoding to Octagon 1\n");
  894. if(inorder==1)
  895. decodefunc = fm_i1_oct1;
  896. else
  897. decodefunc = fm_i2_oct1;
  898. outchans = 8;
  899. break;
  900. case FM_OCT2:
  901. printf("Decoding to Octagon 2\n");
  902. if(inorder==1)
  903. decodefunc = fm_i1_oct2;
  904. else
  905. decodefunc = fm_i2_oct2;
  906. outchans = 8;
  907. break;
  908. case FM_CUBE:
  909. printf("Decoding to Cube (FM interleaved)\n");
  910. if(inorder==1)
  911. decodefunc = fm_i1_cube;
  912. else
  913. decodefunc = fm_i2_cube;
  914. outchans = 8;
  915. break;
  916. case FM_QUADCUBE:
  917. printf("Decoding to Octagon 1 (WAVEX order)\n");
  918. if(inorder==1)
  919. decodefunc = fm_i1_cubex;
  920. else
  921. decodefunc = fm_i2_cubex;
  922. outchans = 8;
  923. break;
  924. default:
  925. //quad
  926. printf("Decoding to quad surround (WAVEX order)\n");
  927. if(inorder == 1)
  928. decodefunc = fm_i1_quad;
  929. else
  930. decodefunc = fm_i2_quad;
  931. outchans = 4;
  932. break;
  933. }
  934. } // MC_BFMT
  935. /* just read peaks for soundfile */
  936. fpeaks = (CHPEAK *) calloc(inchans,sizeof(CHPEAK));
  937. if(fpeaks==NULL){
  938. puts("No memory for PEAK data\n");
  939. goto error;
  940. }
  941. int thispeaktime;
  942. res = sndreadpeaks(sfdata.ifd,inchans,fpeaks, &thispeaktime);
  943. in_peaktime = (time_t) thispeaktime;
  944. if(res==0){
  945. printf("No PEAK data in this file\n");
  946. }
  947. if(res > 0) {
  948. printf("PEAK data:\ncreation time: %s",ctime( &in_peaktime));
  949. for(i=0;i < inchans;i++){
  950. printf("CH %d: %.4f at frame %u: \t%.4f secs\n",
  951. i,fpeaks[i].value,fpeaks[i].position,(double)(fpeaks[i].position / (double) props.srate));
  952. }
  953. }
  954. break;
  955. default:
  956. fprintf(stderr,"\nSorry: Pvplay can only play soundfiles and analysis files.");
  957. return 1;
  958. }
  959. }
  960. /* memory playback mode? */
  961. if(playtype == PLAY_SFILE && nFramesToPlay <= ringframelen){
  962. sfdata.membuf = (float *) PaUtil_AllocateMemory(nFramesToPlay * sizeof(float) * /*inchans*/ outchans);
  963. if( sfdata.membuf == NULL ) {
  964. puts("Could not allocate memory play buffer.\n");
  965. goto error;
  966. }
  967. sfdata.memFramelength = nFramesToPlay;
  968. sfdata.memFramePos = 0;
  969. playcallback = MemCallback;
  970. printf("RAM block size = %lu\n",nFramesToPlay);
  971. }
  972. else {
  973. // set up pcm ring buffer NB must be power of 2 size
  974. if(props.srate > 48000)
  975. ringframelen <<= 1;
  976. printf("File buffer size set to %ld sample frames\n",ringframelen);
  977. // NB ring buffer sized for decoded data, hence outchans here; otherwise inchans = outchans
  978. sfdata.ringbufData = (float *) PaUtil_AllocateMemory( ringframelen * sizeof(float) * outchans); /* From now on, recordedSamples is initialised. */
  979. if( sfdata.ringbufData == NULL ) {
  980. puts("Could not allocate play buffer.\n");
  981. goto error;
  982. }
  983. // number of elements has to be a power of two, so each element has to be a full m/c frame
  984. if (PaUtil_InitializeRingBuffer(&sfdata.ringbuf, sizeof(float) * outchans, ringframelen , sfdata.ringbufData) < 0) {
  985. puts("Could not initialise play buffer.\n");
  986. goto error;
  987. }
  988. }
  989. /* create input side workspace buffer, used for both soundfiles and analysis files! */
  990. sfdata.inbuf = (float *) PaUtil_AllocateMemory(ringframelen * sizeof(float) * inchans);
  991. if(sfdata.inbuf==NULL){
  992. puts("No memory for read buffer\n");
  993. goto error;
  994. }
  995. sfdata.inbuflen = ringframelen;
  996. if(playtype == PLAY_PVXFILE && (inchans==2)){
  997. sfdata.outbuf_l = (float *) PaUtil_AllocateMemory(ringframelen * sizeof(float) );
  998. sfdata.outbuf_r = (float *) PaUtil_AllocateMemory(ringframelen * sizeof(float) );
  999. }
  1000. if(props.srate > 48000)
  1001. frames_per_buffer *= 2;
  1002. if(frames_per_buffer > 0)
  1003. printf("Audio buffer size = %lu\n",frames_per_buffer);
  1004. sfdata.inchans = inchans;
  1005. sfdata.outchans = outchans;
  1006. sfdata.frames_played = 0;
  1007. sfdata.gain = gain;
  1008. sfdata.copyfunc = copyfunc;
  1009. sfdata.decodefunc = decodefunc;
  1010. sfdata.do_decode = flags[FLAG_B];
  1011. sfdata.from_frame = from_frame; // interpreted according to Play Type
  1012. sfdata.to_frame = to_frame;
  1013. sfdata.play_looped = flags[FLAG_L];
  1014. sfdata.srate = props.srate;
  1015. sfdata.finished = 0;
  1016. g_pdata = &sfdata;
  1017. outputParameters.device = device; /*Pa_GetDefaultOutputDevice(); */ /* default output device */
  1018. outputParameters.channelCount = outchans;
  1019. outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output */
  1020. outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
  1021. outputParameters.hostApiSpecificStreamInfo = NULL;
  1022. devinfo = (PaDeviceInfo *) Pa_GetDeviceInfo(device);
  1023. #if defined MAC || defined unix
  1024. if(devinfo){
  1025. printf("Using device %d: %s\n",device,devinfo->name);
  1026. }
  1027. #endif
  1028. #ifdef WIN32
  1029. # ifdef NOTDEF
  1030. if(devinfo){
  1031. if(apiinfo->type == paMME ){
  1032. winmmeStreamInfo.size = sizeof(winmmeStreamInfo);
  1033. winmmeStreamInfo.hostApiType = paMME;
  1034. winmmeStreamInfo.version = 1;
  1035. winmmeStreamInfo.flags = paWinMmeUseChannelMask;
  1036. winmmeStreamInfo.channelMask = 0;
  1037. outputParameters.hostApiSpecificStreamInfo = &winmmeStreamInfo;
  1038. # ifdef _DEBUG
  1039. printf("WIN DEBUG: WinMME device channel mask set to 0.\n");
  1040. # endif
  1041. }
  1042. }
  1043. # endif
  1044. /* change val to 1 if also using MME */
  1045. if(devinfo){
  1046. int apitype = devinfo->hostApi; // get index of api type
  1047. const PaHostApiInfo *apiinfo = Pa_GetHostApiInfo( apitype );
  1048. printf("Using device %d: %s:",device,devinfo->name);
  1049. if(apiinfo->type == paDirectSound) {
  1050. printf ("(DS)\n");
  1051. /* set this IF we are using Dsound device. */
  1052. directSoundStreamInfo.size = sizeof(PaWinDirectSoundStreamInfo);
  1053. directSoundStreamInfo.hostApiType = paDirectSound;
  1054. directSoundStreamInfo.version = 2;
  1055. directSoundStreamInfo.flags = paWinDirectSoundUseChannelMask;
  1056. directSoundStreamInfo.channelMask = speakermask;
  1057. outputParameters.hostApiSpecificStreamInfo = &directSoundStreamInfo;
  1058. }
  1059. else if(apiinfo->type == paASIO)
  1060. printf("(ASIO)\n");
  1061. // else
  1062. // printf("API unknown!);
  1063. }
  1064. #endif
  1065. err = Pa_OpenStream(
  1066. &stream,
  1067. NULL, /* No input */
  1068. &outputParameters, /* As above. */
  1069. props.srate,
  1070. frames_per_buffer, /* Frames per buffer. */
  1071. paClipOff, /* we won't output out of range samples so don't bother clipping them */
  1072. playcallback,
  1073. &sfdata );
  1074. if( err != paNoError ){
  1075. fprintf(stderr,"Unable to open audio device: err = %d\n", err);
  1076. exit(1);
  1077. }
  1078. err = Pa_SetStreamFinishedCallback( stream, finishedCallback );
  1079. if( err != paNoError ) {
  1080. printf("Unable to set finish callback\n");
  1081. goto error;
  1082. }
  1083. sfdata.stream = stream;
  1084. file_playing = 1;
  1085. if(waitkey){
  1086. printf("Press any key to start:\n");
  1087. printf("Hit CTRL-C to stop.\n");
  1088. fflush(stdout);
  1089. while (!kbhit()){
  1090. if(!file_playing) //check for instant CTRL-C
  1091. goto error;
  1092. };
  1093. #ifdef _WIN32
  1094. if(kbhit())
  1095. _getch(); //prevent display of char
  1096. #endif
  1097. }
  1098. // should this go in read thread func too?
  1099. #ifdef NOTDEF
  1100. // TODO: any benefits in using this?
  1101. pterror = Pt_Start(200, porttimeCallback, NULL);
  1102. if(pterror != ptNoError){
  1103. printf("porttime timer failed to initialise!\n");
  1104. return 1;
  1105. }
  1106. #endif
  1107. /* if small block, read it all into memory
  1108. NB not doing paplay channel mapping */
  1109. if(sfdata.memFramelength > 0){
  1110. //if(psf_sndReadFloatFrames(sfdata.ifd,sfdata.membuf,sfdata.memFramelength)
  1111. if(fgetfbufEx(sfdata.membuf,sfdata.memFramelength*sfdata.inchans,sfdata.ifd,0)
  1112. != (int) sfdata.memFramelength*sfdata.inchans) {
  1113. printf("Error reading soundfile into memory\n");
  1114. goto error;
  1115. }
  1116. }
  1117. // set up timer
  1118. #ifdef unix
  1119. if(do_updatemessages) {
  1120. setitimer(ITIMER_REAL, &tout_val,0);
  1121. signal(SIGALRM,alarm_wakeup); /* set the Alarm signal capture */
  1122. }
  1123. #endif
  1124. //#ifdef _WIN32
  1125. // not sure of the best position for this
  1126. //if(!CreateTimerQueueTimer(&sfdata.hTimer, hTimerQueue,
  1127. // (WAITORTIMERCALLBACK) TimerCallback, &sfdata,250,250,0)) {
  1128. // printf("failed to start timer (3).\n");
  1129. // return 1;
  1130. // }
  1131. //#endif
  1132. /* Start the file reading thread */
  1133. sfdata.startTime = Pa_GetStreamTime(stream );
  1134. switch(playtype){
  1135. case PLAY_SFILE:
  1136. if(sfdata.memFramelength == 0){
  1137. err = startThread(&sfdata, threadFunctionReadFromRawFile);
  1138. if( err != paNoError ) goto error;
  1139. }
  1140. else {
  1141. sfdata.flag = 0;
  1142. }
  1143. break;
  1144. case PLAY_ANAFILE:
  1145. err = startThread(&sfdata, threadFunctionReadFromAnalFile);
  1146. if( err != paNoError ) goto error;
  1147. break;
  1148. case PLAY_PVXFILE:
  1149. err = startThread(&sfdata, threadFunctionReadFromPVXFile);
  1150. if( err != paNoError ) goto error;
  1151. break;
  1152. default:
  1153. printf("Internal error: no playback file type!\n");
  1154. return 1;
  1155. }
  1156. #ifdef _WIN32
  1157. if(do_updatemessages){
  1158. if(!CreateTimerQueueTimer(&sfdata.hTimer, hTimerQueue,
  1159. (WAITORTIMERCALLBACK) TimerCallback, &sfdata,200,200,0)) {
  1160. printf("failed to start timer (3).\n");
  1161. return 1;
  1162. }
  1163. }
  1164. #endif
  1165. err = Pa_StartStream( stream );
  1166. if( err != paNoError ) {
  1167. fprintf(stderr,"Unable to start playback.\n");
  1168. goto error;
  1169. }
  1170. while((!sfdata.finished) && file_playing){
  1171. // nothing to do!
  1172. Pa_Sleep(20);
  1173. }
  1174. // note to the curious: any bug in audio buffer arithmetic will likely cause crash here!
  1175. err = Pa_StopStream( stream );
  1176. if( err != paNoError ) {
  1177. printf("Error stopping stream\n");
  1178. goto error;
  1179. }
  1180. /* read thread should exit always, no need to Stop it here */
  1181. err = Pa_CloseStream( stream );
  1182. if( err != paNoError ) {
  1183. printf("Error closing stream\n");
  1184. goto error;
  1185. }
  1186. printf("%.2f secs\n",(float)(sfdata.lastTime));
  1187. fflush(stdout);
  1188. printf("Playback finished.\n");
  1189. error:
  1190. Pa_Terminate();
  1191. #ifdef _WIN32
  1192. CloseHandle(ghEvent);
  1193. DeleteTimerQueue(hTimerQueue);
  1194. #endif
  1195. if( sfdata.ringbufData )
  1196. PaUtil_FreeMemory(sfdata.ringbufData);
  1197. if(sfdata.inbuf)
  1198. PaUtil_FreeMemory(sfdata.inbuf);
  1199. if(sfdata.membuf)
  1200. PaUtil_FreeMemory(sfdata.membuf);
  1201. if(sfdata.outbuf_l)
  1202. PaUtil_FreeMemory(sfdata.outbuf_l);
  1203. if(sfdata.outbuf_r)
  1204. PaUtil_FreeMemory(sfdata.outbuf_r);
  1205. if(sfdata.ifd >= 0)
  1206. sndcloseEx(sfdata.ifd);
  1207. if(sfdata.pvfile >= 0)
  1208. pvoc_closefile(sfdata.pvfile);
  1209. if(fpeaks)
  1210. free(fpeaks);
  1211. // sffinish();
  1212. pvsys_release();
  1213. if(err != paNoError){
  1214. fprintf( stderr, "An error occured while using the portaudio stream\n" );
  1215. fprintf( stderr, "Error number: %d\n", err );
  1216. fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
  1217. return err;
  1218. }
  1219. return 0;
  1220. }
  1221. int show_devices(void)
  1222. {
  1223. // int i,j;
  1224. PaDeviceIndex numDevices,p;
  1225. const PaDeviceInfo *pdi;
  1226. #ifdef _WIN32
  1227. const PaHostApiInfo* api_info;
  1228. #endif
  1229. PaError err;
  1230. // int nOutputDevices = 0;
  1231. #ifdef USE_ASIO
  1232. printf("For ASIO multi-channel, you may need to select the highest device no.\n");
  1233. #endif
  1234. /*Pa_Initialize();*/
  1235. numDevices = Pa_GetDeviceCount();
  1236. if( numDevices < 0 )
  1237. {
  1238. printf("ERROR: Pa_CountDevices returned 0x%x\n", numDevices );
  1239. err = numDevices;
  1240. return err;
  1241. }
  1242. #ifdef WIN32
  1243. printf("Driver\tDevice\tInput\tOutput\tName\n");
  1244. #else
  1245. printf("Device\tInput\tOutput\tName\n");
  1246. #endif
  1247. //printf("Number of devices = %d\n", numDevices );
  1248. for( p=0; p<numDevices; p++ )
  1249. {
  1250. pdi = Pa_GetDeviceInfo( p );
  1251. // nOutputDevices++;
  1252. if( p == Pa_GetDefaultOutputDevice() )
  1253. printf("*");
  1254. else
  1255. printf(" ");
  1256. #ifdef WIN32
  1257. api_info = Pa_GetHostApiInfo(pdi->hostApi);
  1258. const char *apiname = api_info->name;
  1259. if(strcmp(apiname,"Windows DirectSound")==0)
  1260. apiname = "DS ";
  1261. printf("(%s)\t%d\t%d\t%d\t%s\n",apiname,p,
  1262. pdi->maxInputChannels,
  1263. pdi->maxOutputChannels,
  1264. pdi->name);
  1265. #else
  1266. printf("%d\t%d\t%d\t%s\n",p,
  1267. pdi->maxInputChannels,
  1268. pdi->maxOutputChannels,
  1269. pdi->name);
  1270. #endif
  1271. }
  1272. /*Pa_Terminate();*/
  1273. return 0;
  1274. }
  1275. #ifdef unix
  1276. int stricmp(const char *a, const char *b)
  1277. {
  1278. while(*a != '\0' && *b != '\0') {
  1279. int ca = islower(*a) ? toupper(*a) : *a;
  1280. int cb = islower(*b) ? toupper(*b) : *b;
  1281. if(ca < cb)
  1282. return -1;
  1283. if(ca > cb)
  1284. return 1;
  1285. a++;
  1286. b++;
  1287. }
  1288. if(*a == '\0' && *b == '\0')
  1289. return 0;
  1290. if(*a != '\0')
  1291. return 1;
  1292. return -1;
  1293. }
  1294. int
  1295. strnicmp(const char *a, const char *b, const int length)
  1296. {
  1297. int len = length;
  1298. while(*a != '\0' && *b != '\0') {
  1299. int ca = islower(*a) ? toupper(*a) : *a;
  1300. int cb = islower(*b) ? toupper(*b) : *b;
  1301. if(len-- < 1)
  1302. return 0;
  1303. if(ca < cb)
  1304. return -1;
  1305. if(ca > cb)
  1306. return 1;
  1307. a++;
  1308. b++;
  1309. }
  1310. if(*a == '\0' && *b == '\0')
  1311. return 0;
  1312. if(*a != '\0')
  1313. return 1;
  1314. return -1;
  1315. }
  1316. #endif