Julius 4.1.5
|
00001 00062 /* 00063 * Copyright (c) 2004-2005 Shikano Lab., Nara Institute of Science and Technology 00064 * Copyright (c) 2005-2007 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; 00197 #else 00198 static PaStream *stream; 00199 #endif 00200 00209 boolean 00210 adin_mic_standby(int sfreq, void *dummy) 00211 { 00212 PaError err; 00213 #ifdef OLDVER 00214 int frames_per_buffer; 00215 int num_buffer; 00216 #endif 00217 int latency; 00218 char *p; 00219 00220 /* set cycle buffer length */ 00221 cycle_buffer_len = INPUT_DELAY_SEC * sfreq; 00222 jlog("Stat: adin_portaudio: INPUT_DELAY_SEC = %d\n", INPUT_DELAY_SEC); 00223 jlog("Stat: adin_portaudio: audio cycle buffer length = %d bytes\n", cycle_buffer_len * sizeof(SP16)); 00224 00225 #ifdef OLDVER 00226 /* for safety... */ 00227 if (sizeof(SP16) != paInt16) { 00228 jlog("Error: adin_portaudio: SP16 != paInt16 !!\n"); 00229 return FALSE; 00230 } 00231 /* set buffer parameter*/ 00232 frames_per_buffer = 256; 00233 #endif 00234 00235 /* allocate and init */ 00236 current = processed = 0; 00237 speech = (SP16 *)mymalloc(sizeof(SP16) * cycle_buffer_len); 00238 buffer_overflowed = FALSE; 00239 00240 00241 /* get user-specified latency parameter */ 00242 latency = 0; 00243 if ((p = getenv("LATENCY_MSEC")) != NULL) { 00244 latency = atoi(p); 00245 jlog("Stat: adin_portaudio: setting latency to %d msec (obtained from LATENCY_MSEC)\n", latency); 00246 } 00247 #ifdef OLDVER 00248 if (latency == 0) { 00249 latency = MAX_FRAGMENT_MSEC; 00250 jlog("Stat: adin_portaudio: setting latency to %d msec\n", latency); 00251 } 00252 num_buffer = sfreq * latency / (frames_per_buffer * 1000); 00253 jlog("Stat: adin_portaudio: framesPerBuffer=%d, NumBuffers(guess)=%d\n", 00254 frames_per_buffer, num_buffer); 00255 jlog("Stat: adin_portaudio: audio I/O Latency = %d msec (data fragment = %d frames)\n", 00256 (frames_per_buffer * num_buffer) * 1000 / sfreq, 00257 (frames_per_buffer * num_buffer)); 00258 #endif 00259 00260 /* initialize device */ 00261 err = Pa_Initialize(); 00262 if (err != paNoError) { 00263 jlog("Error: adin_portaudio: failed to initialize: %s\n", Pa_GetErrorText(err)); 00264 return(FALSE); 00265 } 00266 00267 #ifdef CHOOSE_HOST_API 00268 00269 { 00270 // choose a device to open 00271 // For win32, preference order is WASAPI > ASIO > DirectSound > MME 00272 // If several device matches the first found one will be used. 00273 int devId; 00274 PaDeviceIndex numDevice = Pa_GetDeviceCount(), i; 00275 const PaDeviceInfo *deviceInfo; 00276 const PaHostApiInfo *apiInfo; 00277 PaStreamParameters param; 00278 char *devname; 00279 static char buf[256]; 00280 #ifdef _WIN32 00281 // at win32, force preference order: iWASAPI > ASIO > DirectSound > MME > Other 00282 int iMME = -1, iDS = -1, iASIO = -1, iWASAPI = -1; 00283 #endif 00284 00285 // if PORTAUDIO_DEV is specified, match it against available APIs 00286 devname = getenv("PORTAUDIO_DEV"); 00287 devId = -1; 00288 00289 // get list of available capture devices 00290 jlog("Stat: adin_portaudio: available capture devices:\n"); 00291 for(i=0;i<numDevice;i++) { 00292 deviceInfo = Pa_GetDeviceInfo(i); 00293 if (!deviceInfo) continue; 00294 if (deviceInfo->maxInputChannels <= 0) continue; 00295 apiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); 00296 if (!apiInfo) continue; 00297 snprintf(buf, 255, "%s: %s", apiInfo->name, deviceInfo->name); 00298 buf[255] = '\0'; 00299 jlog(" #%d [%s]\n", i+1, buf); 00300 if (devname && !strncmp(devname, buf, strlen(devname))) { 00301 // device name (partially) matches PORTAUDIO_DEV 00302 devId = i; 00303 } 00304 #ifdef _WIN32 00305 // store the device ID for each API 00306 switch(apiInfo->type) { 00307 case paWASAPI: if (iWASAPI < 0) iWASAPI = i; break; 00308 case paMME:if (iMME < 0) iMME = i; break; 00309 case paDirectSound:if (iDS < 0) iDS = i; break; 00310 case paASIO:if (iASIO < 0) iASIO = i; break; 00311 } 00312 #endif 00313 } 00314 if (devId != -1) { 00315 jlog(" --> #%d matches PORTAUDIO_DEV, use it\n", devId + 1); 00316 } 00317 if (devId == -1) { 00318 if (getenv("PORTAUDIO_DEV_NUM")) { 00319 devId = atoi(getenv("PORTAUDIO_DEV_NUM")) - 1; 00320 jlog(" --> use #%d, specified by PORTAUDIO_DEV_NUM\n", devId + 1); 00321 } 00322 } 00323 #ifdef _WIN32 00324 if (devId == -1) { 00325 // if PORTAUDIO_DEV not specified or not matched, use device in the preference order. 00326 if (iWASAPI >= 0) devId = iWASAPI; 00327 else if (iASIO >= 0) devId = iASIO; 00328 else if (iDS >= 0) devId = iDS; 00329 else if (iMME >= 0) devId = iMME; 00330 else devId = -1; 00331 } 00332 #endif 00333 if (devId == -1) { 00334 // No device has been found, try to get the default input device 00335 devId = Pa_GetDefaultInputDevice(); 00336 if (devId == paNoDevice) { 00337 jlog("Error: adin_portaudio: no default input device is available or an error was encountered\n"); 00338 return FALSE; 00339 } 00340 } 00341 // output device information 00342 deviceInfo = Pa_GetDeviceInfo(devId); 00343 apiInfo = Pa_GetHostApiInfo(deviceInfo->hostApi); 00344 snprintf(buf, 255, "%s: %s", apiInfo->name, deviceInfo->name); 00345 buf[255] = '\0'; 00346 jlog("Stat: adin_portaudio: get input from: [%s]\n", buf); 00347 jlog("Info: adin_portaudio: set \"PORTAUDIO_DEV\" to the string in \"[]\" above to change\n"); 00348 00349 // open the device 00350 memset( ¶m, 0, sizeof(param)); 00351 param.channelCount = 1; 00352 param.device = devId; 00353 param.sampleFormat = paInt16; 00354 if (latency == 0) { 00355 param.suggestedLatency = Pa_GetDeviceInfo(devId)->defaultLowInputLatency; 00356 jlog("Stat: adin_portaudio: try to set default low latency from portaudio: %d msec\n", param.suggestedLatency * 1000.0); 00357 } else { 00358 param.suggestedLatency = latency / 1000.0; 00359 jlog("Stat: adin_portaudio: try to set latency to %d msec\n", param.suggestedLatency * 1000.0); 00360 } 00361 err = Pa_OpenStream(&stream, ¶m, NULL, sfreq, 00362 0, paNoFlag, 00363 Callback, NULL); 00364 if (err != paNoError) { 00365 jlog("Error: adin_portaudio: error in opening stream: %s\n", Pa_GetErrorText(err)); 00366 return(FALSE); 00367 } 00368 { 00369 const PaStreamInfo *stinfo; 00370 stinfo = Pa_GetStreamInfo(stream); 00371 jlog("Stat: adin_portaudio: latency was set to %f msec\n", stinfo->inputLatency * 1000.0); 00372 } 00373 } 00374 00375 #else 00376 00377 err = Pa_OpenDefaultStream(&stream, 1, 0, paInt16, sfreq, 00378 #ifdef OLDVER 00379 frames_per_buffer, 00380 num_buffer, 00381 #else 00382 0, 00383 #endif 00384 Callback, NULL); 00385 if (err != paNoError) { 00386 jlog("Error: adin_portaudio: error in opening stream: %s\n", Pa_GetErrorText(err)); 00387 return(FALSE); 00388 } 00389 00390 #endif /* CHOOSE_HOST_API */ 00391 00392 return(TRUE); 00393 } 00394 00402 boolean 00403 adin_mic_begin(char *pathname) 00404 { 00405 PaError err; 00406 00407 /* start stream */ 00408 err = Pa_StartStream(stream); 00409 if (err != paNoError) { 00410 jlog("Error: adin_portaudio: failed to begin stream: %s\n", Pa_GetErrorText(err)); 00411 return(FALSE); 00412 } 00413 00414 return(TRUE); 00415 } 00416 00422 boolean 00423 adin_mic_end() 00424 { 00425 PaError err; 00426 00427 /* stop stream */ 00428 err = Pa_StopStream(stream); 00429 if (err != paNoError) { 00430 jlog("Error: adin_portaudio: failed to stop stream: %s\n", Pa_GetErrorText(err)); 00431 return(FALSE); 00432 } 00433 00434 return TRUE; 00435 } 00436 00449 int 00450 adin_mic_read(SP16 *buf, int sampnum) 00451 { 00452 int current_local; 00453 int avail; 00454 int len; 00455 00456 if (buffer_overflowed) { 00457 jlog("Error: adin_portaudio: input buffer OVERFLOW, increase INPUT_DELAY_SEC in sent/speech.h\n"); 00458 buffer_overflowed = FALSE; 00459 } 00460 00461 while (current == processed) { 00462 #ifdef DDEBUG 00463 printf("process : current == processed: %d: wait\n", current); 00464 #endif 00465 Pa_Sleep(20); /* wait till some input comes */ 00466 } 00467 00468 current_local = current; 00469 00470 #ifdef DDEBUG 00471 printf("process-1: processed=%d, current=%d\n", processed, current_local); 00472 #endif 00473 00474 if (processed < current_local) { 00475 avail = current_local - processed; 00476 if (avail > sampnum) avail = sampnum; 00477 memcpy(buf, &(speech[processed]), avail * sizeof(SP16)); 00478 #ifdef DDEBUG 00479 printf("process-2: [%d..%d] %d samples read\n", processed, processed+avail, avail); 00480 #endif 00481 len = avail; 00482 processed += avail; 00483 } else { 00484 avail = cycle_buffer_len - processed; 00485 if (avail > sampnum) avail = sampnum; 00486 memcpy(buf, &(speech[processed]), avail * sizeof(SP16)); 00487 #ifdef DDEBUG 00488 printf("process-2-1: [%d..%d] %d samples read\n", processed, processed+avail, avail); 00489 #endif 00490 len = avail; 00491 processed += avail; 00492 if (processed >= cycle_buffer_len) processed -= cycle_buffer_len; 00493 if (sampnum - avail > 0) { 00494 if (sampnum - avail < current_local) { 00495 avail = sampnum - avail; 00496 } else { 00497 avail = current_local; 00498 } 00499 if (avail > 0) { 00500 memcpy(&(buf[len]), &(speech[0]), avail * sizeof(SP16)); 00501 #ifdef DDEBUG 00502 printf("process-2-2: [%d..%d] %d samples read (total %d)\n", 0, avail, avail, len + avail); 00503 #endif 00504 len += avail; 00505 processed += avail; 00506 if (processed >= cycle_buffer_len) processed -= cycle_buffer_len; 00507 } 00508 } 00509 } 00510 #ifdef DDEBUG 00511 printf("process-3: new processed: %d\n", processed); 00512 #endif 00513 return len; 00514 } 00515 00523 char * 00524 adin_mic_input_name() 00525 { 00526 return("Portaudio default device"); 00527 }