Julius 4.2
|
00001 00062 /* 00063 * Copyright (c) 2004-2005 Shikano Lab., Nara Institute of Science and Technology 00064 * Copyright (c) 2005-2011 Julius project team, Nagoya Institute of Technology 00065 * All rights reserved 00066 */ 00067 00068 #include <sent/stddefs.h> 00069 #include <sent/speech.h> 00070 #include <sent/adin.h> 00071 00072 /* sound header */ 00073 #include <portaudio.h> 00074 00075 #ifndef paNonInterleaved 00076 #define OLDVER 00077 #endif 00078 00079 #undef DDEBUG 00080 00094 #ifndef OLDVER 00095 #define CHOOSE_HOST_API 00096 #endif 00097 00107 #ifdef OLDVER 00108 #define MAX_FRAGMENT_MSEC 128 00109 #endif 00110 00111 /* temporal buffer */ 00112 static SP16 *speech; 00113 static int current; 00114 static int processed; 00115 static boolean buffer_overflowed = FALSE; 00116 static int cycle_buffer_len; 00117 00130 static int 00131 #ifdef OLDVER 00132 Callback(void *inbuf, void *outbuf, unsigned long len, PaTimestamp outTime, void *userdata) 00133 #else 00134 Callback(const void *inbuf, void *outbuf, unsigned long len, const PaStreamCallbackTimeInfo *outTime, PaStreamCallbackFlags statusFlags, void *userdata) 00135 #endif 00136 { 00137 #ifdef OLDVER 00138 SP16 *now; 00139 int avail; 00140 #else 00141 const SP16 *now; 00142 unsigned long avail; 00143 #endif 00144 int processed_local; 00145 int written; 00146 00147 now = inbuf; 00148 00149 processed_local = processed; 00150 00151 #ifdef DDEBUG 00152 printf("callback-1: processed=%d, current=%d: recordlen=%d\n", processed_local, current, len); 00153 #endif 00154 00155 /* check overflow */ 00156 if (processed_local > current) { 00157 avail = processed_local - current; 00158 } else { 00159 avail = cycle_buffer_len + processed_local - current; 00160 } 00161 if (len > avail) { 00162 #ifdef DDEBUG 00163 printf("callback-*: buffer overflow!\n"); 00164 #endif 00165 buffer_overflowed = TRUE; 00166 len = avail; 00167 } 00168 00169 /* store to buffer */ 00170 if (current + len <= cycle_buffer_len) { 00171 memcpy(&(speech[current]), now, len * sizeof(SP16)); 00172 #ifdef DDEBUG 00173 printf("callback-2: [%d..%d] %d samples written\n", current, current+len, len); 00174 #endif 00175 } else { 00176 written = cycle_buffer_len - current; 00177 memcpy(&(speech[current]), now, written * sizeof(SP16)); 00178 #ifdef DDEBUG 00179 printf("callback-2-1: [%d..%d] %d samples written\n", current, current+written, written); 00180 #endif 00181 memcpy(&(speech[0]), &(now[written]), (len - written) * sizeof(SP16)); 00182 #ifdef DDEBUG 00183 printf("callback-2-2: ->[%d..%d] %d samples written (total %d samples)\n", 0, len-written, len-written, len); 00184 #endif 00185 } 00186 current += len; 00187 if (current >= cycle_buffer_len) current -= cycle_buffer_len; 00188 #ifdef DDEBUG 00189 printf("callback-3: new current: %d\n", current); 00190 #endif 00191 00192 return(0); 00193 } 00194 00195 #ifdef OLDVER 00196 static PortAudioStream *stream = NULL; 00197 #else 00198 static PaStream *stream = NULL; 00199 #endif 00200 static int srate; 00201 00202 00203 #ifdef CHOOSE_HOST_API 00204 00205 // Get device list 00206 // If first argument is NULL, return the maximum number of devices 00207 int 00208 get_device_list(int *devidlist, char **namelist, int maxstrlen, int maxnum) 00209 { 00210 PaDeviceIndex numDevice = Pa_GetDeviceCount(), i; 00211 const PaDeviceInfo *deviceInfo; 00212 const PaHostApiInfo *apiInfo; 00213 static char buf[256]; 00214 int n; 00215 00216 n = 0; 00217 for(i=0;i<numDevice;i++) { 00218 deviceInfo = Pa_GetDeviceInfo(i); 00219 if (!deviceInfo) continue; 00220 if (deviceInfo->maxInputChannels <= 0) continue; 00221 apiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); 00222 if (!apiInfo) continue; 00223 if (devidlist != NULL) { 00224 if ( n >= maxnum ) break; 00225 snprintf(buf, 255, "%s: %s", apiInfo->name, deviceInfo->name); 00226 buf[255] = '\0'; 00227 devidlist[n] = i; 00228 strncpy(namelist[n], buf, maxstrlen); 00229 } 00230 n++; 00231 } 00232 00233 return n; 00234 } 00235 00236 // Automatically choose a device to open 00237 // 00238 // 1. if the env value of "PORTAUDIO_DEV" is defined and matches any of 00239 // "apiInfo->name: deviceInfo->name" string, use it. 00240 // 2. if the env value "PORTAUDIO_DEV_NUM" is defined, use the (value-1) 00241 // as device id. 00242 // 3. if not yet, default device will be chosen: 00243 // 3.1. in WIN32 environment, search for supported and available API in 00244 // the following order: WASAPI, ASIO, DirectSound, MME. 00245 // Note that only the APIs supported by the linked PortAudio 00246 // library are available. 00247 // 3.2 in other environment, use the default input device. 00248 // 00249 // store the device id to devId_ret and returns 0. 00250 // if devId_ret is -1, tell caller to use default. 00251 // returns -1 on error. 00252 static int 00253 auto_determine_device(int *devId_ret) 00254 { 00255 int devId; 00256 PaDeviceIndex numDevice = Pa_GetDeviceCount(), i; 00257 const PaDeviceInfo *deviceInfo; 00258 const PaHostApiInfo *apiInfo; 00259 char *devname; 00260 static char buf[256]; 00261 #if defined(_WIN32) || defined(__CYGWIN__) 00262 // at win32, force preference order: iWASAPI > ASIO > DirectSound > MME > Other 00263 int iMME = -1, iDS = -1, iASIO = -1, iWASAPI = -1; 00264 #endif 00265 00266 // if PORTAUDIO_DEV is specified, match it against available APIs 00267 devname = getenv("PORTAUDIO_DEV"); 00268 devId = -1; 00269 00270 // get list of available capture devices 00271 jlog("Stat: adin_portaudio: sound capture devices:\n"); 00272 for(i=0;i<numDevice;i++) { 00273 deviceInfo = Pa_GetDeviceInfo(i); 00274 if (!deviceInfo) continue; 00275 if (deviceInfo->maxInputChannels <= 0) continue; 00276 apiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); 00277 if (!apiInfo) continue; 00278 snprintf(buf, 255, "%s: %s", apiInfo->name, deviceInfo->name); 00279 buf[255] = '\0'; 00280 jlog(" %d [%s]\n", i+1, buf); 00281 if (devname && !strncmp(devname, buf, strlen(devname))) { 00282 // device name (partially) matches PORTAUDIO_DEV 00283 devId = i; 00284 } 00285 #if defined(_WIN32) || defined(__CYGWIN__) 00286 // store the device ID for each API 00287 switch(apiInfo->type) { 00288 case paWASAPI: if (iWASAPI < 0) iWASAPI = i; break; 00289 case paMME:if (iMME < 0) iMME = i; break; 00290 case paDirectSound:if (iDS < 0) iDS = i; break; 00291 case paASIO:if (iASIO < 0) iASIO = i; break; 00292 } 00293 #endif 00294 } 00295 if (devname) { 00296 if (devId == -1) { 00297 jlog("Error: adin_portaudio: PORTAUDIO_DEV=\"%s\", but no device matches it\n", devname); 00298 return -1; 00299 } 00300 jlog(" --> #%d matches PORTAUDIO_DEV, use it\n", devId + 1); 00301 *devId_ret = devId; 00302 return 0; 00303 } 00304 if (getenv("PORTAUDIO_DEV_NUM")) { 00305 devId = atoi(getenv("PORTAUDIO_DEV_NUM")) - 1; 00306 if (devId < 0 || devId >= numDevice) { 00307 jlog("Error: PORTAUDIO_DEV_NUM=%d, but device %d not exist\n", devId+1, devId+1); 00308 return -1; 00309 } 00310 jlog(" --> use device %d, specified by PORTAUDIO_DEV_NUM\n", devId + 1); 00311 *devId_ret = devId; 00312 return 0; 00313 } 00314 #if defined(_WIN32) || defined(__CYGWIN__) 00315 jlog("Stat: adin_portaudio: APIs:"); 00316 if (iWASAPI >= 0) jlog(" WASAPI"); 00317 if (iASIO >= 0) jlog(" ASIO"); 00318 if (iDS >= 0) jlog(" DirectSound"); 00319 if (iMME >= 0) jlog(" MME"); 00320 jlog("\n"); 00321 if (iWASAPI >= 0) { 00322 jlog("Stat: adin_portaudio: -- WASAPI selected\n"); 00323 devId = iWASAPI; 00324 } else if (iASIO >= 0) { 00325 jlog("Stat: adin_portaudio: -- ASIO selected\n"); 00326 devId = iASIO; 00327 } else if (iDS >= 0) { 00328 jlog("Stat: adin_portaudio: -- DirectSound selected\n"); 00329 devId = iDS; 00330 } else if (iMME >= 0) { 00331 jlog("Stat: adin_portaudio: -- MME selected\n"); 00332 devId = iMME; 00333 } else { 00334 jlog("Error: adin_portaudio: no device available, try default\n"); 00335 devId = -1; 00336 } 00337 *devId_ret = devId; 00338 #else 00339 jlog("Stat: adin_portaudio: use default device\n"); 00340 *devId_ret = -1; 00341 #endif 00342 return 0; 00343 } 00344 00345 #endif 00346 00355 boolean 00356 adin_mic_standby(int sfreq, void *dummy) 00357 { 00358 /* store required sampling rate for checking after opening device */ 00359 srate = sfreq; 00360 return TRUE; 00361 } 00362 00370 static boolean 00371 adin_mic_open(char *arg) 00372 { 00373 int sfreq = srate; 00374 PaError err; 00375 #ifdef OLDVER 00376 int frames_per_buffer; 00377 int num_buffer; 00378 #endif 00379 int latency; 00380 char *p; 00381 int devId; 00382 00383 /* set cycle buffer length */ 00384 cycle_buffer_len = INPUT_DELAY_SEC * sfreq; 00385 //jlog("Stat: adin_portaudio: INPUT_DELAY_SEC = %d\n", INPUT_DELAY_SEC); 00386 jlog("Stat: adin_portaudio: audio cycle buffer length = %d bytes\n", cycle_buffer_len * sizeof(SP16)); 00387 00388 #ifdef OLDVER 00389 /* for safety... */ 00390 if (sizeof(SP16) != paInt16) { 00391 jlog("Error: adin_portaudio: SP16 != paInt16 !!\n"); 00392 return FALSE; 00393 } 00394 /* set buffer parameter*/ 00395 frames_per_buffer = 256; 00396 #endif 00397 00398 /* allocate and init */ 00399 current = processed = 0; 00400 speech = (SP16 *)mymalloc(sizeof(SP16) * cycle_buffer_len); 00401 buffer_overflowed = FALSE; 00402 00403 00404 /* get user-specified latency parameter */ 00405 latency = 0; 00406 if ((p = getenv("LATENCY_MSEC")) != NULL) { 00407 latency = atoi(p); 00408 jlog("Stat: adin_portaudio: setting latency to %d msec (obtained from LATENCY_MSEC)\n", latency); 00409 } 00410 #ifdef OLDVER 00411 if (latency == 0) { 00412 latency = MAX_FRAGMENT_MSEC; 00413 jlog("Stat: adin_portaudio: setting latency to %d msec\n", latency); 00414 } 00415 num_buffer = sfreq * latency / (frames_per_buffer * 1000); 00416 jlog("Stat: adin_portaudio: framesPerBuffer=%d, NumBuffers(guess)=%d\n", 00417 frames_per_buffer, num_buffer); 00418 jlog("Stat: adin_portaudio: audio I/O Latency = %d msec (data fragment = %d frames)\n", 00419 (frames_per_buffer * num_buffer) * 1000 / sfreq, 00420 (frames_per_buffer * num_buffer)); 00421 #endif 00422 00423 /* initialize device */ 00424 err = Pa_Initialize(); 00425 if (err != paNoError) { 00426 jlog("Error: adin_portaudio: failed to initialize: %s\n", Pa_GetErrorText(err)); 00427 return(FALSE); 00428 } 00429 00430 #ifdef CHOOSE_HOST_API 00431 00432 if (arg == NULL) { 00433 // first try to determine the best device 00434 if (auto_determine_device(&devId) == -1) { 00435 jlog("Error: adin_portaudio: failed to choose the specified device\n"); 00436 return(FALSE); 00437 } 00438 if (devId == -1) { 00439 // No device has been determined, use the default input device 00440 devId = Pa_GetDefaultInputDevice(); 00441 if (devId == paNoDevice) { 00442 jlog("Error: adin_portaudio: no default input device is available or an error was encountered\n"); 00443 return FALSE; 00444 } 00445 } 00446 } else { 00447 // use the given number as device id 00448 devId = atoi(arg); 00449 } 00450 // output device information to use 00451 { 00452 const PaDeviceInfo *deviceInfo; 00453 const PaHostApiInfo *apiInfo; 00454 static char buf[256]; 00455 deviceInfo = Pa_GetDeviceInfo(devId); 00456 if (deviceInfo == NULL) { 00457 jlog("Error: adin_portaudio: failed to get info for device id %d\n", devId); 00458 return FALSE; 00459 } 00460 apiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); 00461 if (apiInfo == NULL) { 00462 jlog("Error: adin_portaudio: failed to get API info for device id %d\n", devId); 00463 return FALSE; 00464 } 00465 snprintf(buf, 255, "%s: %s", apiInfo->name, deviceInfo->name); 00466 buf[255] = '\0'; 00467 jlog("Stat: adin_portaudio: [%s]\n", buf); 00468 jlog("Stat: adin_portaudio: (you can specify device by \"PORTAUDIO_DEV_NUM=number\"\n"); 00469 } 00470 00471 // open the device 00472 { 00473 PaStreamParameters param; 00474 memset( ¶m, 0, sizeof(param)); 00475 param.channelCount = 1; 00476 param.device = devId; 00477 param.sampleFormat = paInt16; 00478 if (latency == 0) { 00479 param.suggestedLatency = Pa_GetDeviceInfo(devId)->defaultLowInputLatency; 00480 jlog("Stat: adin_portaudio: try to set default low latency from portaudio: %d msec\n", param.suggestedLatency * 1000.0); 00481 } else { 00482 param.suggestedLatency = latency / 1000.0; 00483 jlog("Stat: adin_portaudio: try to set latency to %d msec\n", param.suggestedLatency * 1000.0); 00484 } 00485 err = Pa_OpenStream(&stream, ¶m, NULL, sfreq, 00486 0, paNoFlag, 00487 Callback, NULL); 00488 if (err != paNoError) { 00489 jlog("Error: adin_portaudio: error in opening stream: %s\n", Pa_GetErrorText(err)); 00490 return(FALSE); 00491 } 00492 } 00493 { 00494 const PaStreamInfo *stinfo; 00495 stinfo = Pa_GetStreamInfo(stream); 00496 jlog("Stat: adin_portaudio: latency was set to %f msec\n", stinfo->inputLatency * 1000.0); 00497 } 00498 00499 #else 00500 00501 // Just open the default stream 00502 err = Pa_OpenDefaultStream(&stream, 1, 0, paInt16, sfreq, 00503 #ifdef OLDVER 00504 frames_per_buffer, 00505 num_buffer, 00506 #else 00507 0, 00508 #endif 00509 Callback, NULL); 00510 if (err != paNoError) { 00511 jlog("Error: adin_portaudio: error in opening stream: %s\n", Pa_GetErrorText(err)); 00512 return(FALSE); 00513 } 00514 00515 #endif /* CHOOSE_HOST_API */ 00516 00517 return(TRUE); 00518 } 00519 00527 boolean 00528 adin_mic_begin(char *arg) 00529 { 00530 PaError err; 00531 00532 /* initialize device and open stream */ 00533 if (adin_mic_open(arg) == FALSE) { 00534 stream = NULL; 00535 return(FALSE); 00536 } 00537 /* start stream */ 00538 err = Pa_StartStream(stream); 00539 if (err != paNoError) { 00540 jlog("Error: adin_portaudio: failed to begin stream: %s\n", Pa_GetErrorText(err)); 00541 stream = NULL; 00542 return(FALSE); 00543 } 00544 00545 return(TRUE); 00546 } 00547 00553 boolean 00554 adin_mic_end() 00555 { 00556 PaError err; 00557 00558 if (stream == NULL) return(TRUE); 00559 00560 /* stop stream (do not wait callback and buffer flush, stop immediately) */ 00561 err = Pa_AbortStream(stream); 00562 if (err != paNoError) { 00563 jlog("Error: adin_portaudio: failed to stop stream: %s\n", Pa_GetErrorText(err)); 00564 return(FALSE); 00565 } 00566 /* close stream */ 00567 err = Pa_CloseStream(stream); 00568 if (err != paNoError) { 00569 jlog("Error: adin_portaudio: failed to close stream: %s\n", Pa_GetErrorText(err)); 00570 return(FALSE); 00571 } 00572 /* terminate library */ 00573 err = Pa_Terminate(); 00574 if (err != paNoError) { 00575 jlog("Error: adin_portaudio: failed to terminate library: %s\n", Pa_GetErrorText(err)); 00576 return(FALSE); 00577 } 00578 00579 stream = NULL; 00580 00581 return TRUE; 00582 } 00583 00596 int 00597 adin_mic_read(SP16 *buf, int sampnum) 00598 { 00599 int current_local; 00600 int avail; 00601 int len; 00602 00603 if (buffer_overflowed) { 00604 jlog("Error: adin_portaudio: input buffer OVERFLOW, increase INPUT_DELAY_SEC in sent/speech.h\n"); 00605 buffer_overflowed = FALSE; 00606 } 00607 00608 while (current == processed) { 00609 #ifdef DDEBUG 00610 printf("process : current == processed: %d: wait\n", current); 00611 #endif 00612 Pa_Sleep(20); /* wait till some input comes */ 00613 if (stream == NULL) return(-1); 00614 } 00615 00616 current_local = current; 00617 00618 #ifdef DDEBUG 00619 printf("process-1: processed=%d, current=%d\n", processed, current_local); 00620 #endif 00621 00622 if (processed < current_local) { 00623 avail = current_local - processed; 00624 if (avail > sampnum) avail = sampnum; 00625 memcpy(buf, &(speech[processed]), avail * sizeof(SP16)); 00626 #ifdef DDEBUG 00627 printf("process-2: [%d..%d] %d samples read\n", processed, processed+avail, avail); 00628 #endif 00629 len = avail; 00630 processed += avail; 00631 } else { 00632 avail = cycle_buffer_len - processed; 00633 if (avail > sampnum) avail = sampnum; 00634 memcpy(buf, &(speech[processed]), avail * sizeof(SP16)); 00635 #ifdef DDEBUG 00636 printf("process-2-1: [%d..%d] %d samples read\n", processed, processed+avail, avail); 00637 #endif 00638 len = avail; 00639 processed += avail; 00640 if (processed >= cycle_buffer_len) processed -= cycle_buffer_len; 00641 if (sampnum - avail > 0) { 00642 if (sampnum - avail < current_local) { 00643 avail = sampnum - avail; 00644 } else { 00645 avail = current_local; 00646 } 00647 if (avail > 0) { 00648 memcpy(&(buf[len]), &(speech[0]), avail * sizeof(SP16)); 00649 #ifdef DDEBUG 00650 printf("process-2-2: [%d..%d] %d samples read (total %d)\n", 0, avail, avail, len + avail); 00651 #endif 00652 len += avail; 00653 processed += avail; 00654 if (processed >= cycle_buffer_len) processed -= cycle_buffer_len; 00655 } 00656 } 00657 } 00658 #ifdef DDEBUG 00659 printf("process-3: new processed: %d\n", processed); 00660 #endif 00661 return len; 00662 } 00663 00671 char * 00672 adin_mic_input_name() 00673 { 00674 return("Portaudio default device"); 00675 }