/* AIX UMS sound module. Biggest weirdo thing in here besides the include "gen_drv.c" (legacy) is that there is a bug in the AIX UMS sound support. UMS won't play sound unless there are at least 8k (?) samples submitted. Because this is almost a second when playing 8-bit 11kHz mono sound, the latency would kill the usefulness. So the sound driver plays at 44kHz in 16-bit stereo simply so that it can submit 8k chunks without hurting the sound latency. Seeing as how we were 16-bit, gen_drv.c was modified to support 13-bit mixing instead of 8-bit. The clip was deferred until the output step to avoid an extra pass over the 13-bit buffer. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include void output_samples(short *buf); void sound_uninit(); int sound_init(); #define BUF_SIZE 512 static UMSAudioDevice audio_device; static UMSAudioTypes_Buffer output_buffer; static Environment *audio_env; static int output_buffer_samples; static float usecs_per_samplepair; static int samplepair_latency; static short *output_buffer_data; static int last_sample; static char str[1024]; #include "gen_drv.c" void output_samples(short *buf) { long samplepairs_written; long samplepairs_en_route; int i; int delta; int d_prev; int d_next; output_buffer._length = output_buffer._maximum; // translate 13-bit mono 11kHz (1k) output buffer to linearly interpolated // 16-bit stereo 44kHz output buffer (8k). for smooth transition between // buffers, first sample must be remembered from the last buffer. d_prev = last_sample; d_next = buf[0] << 3; if (d_next < -32768) d_next = -32768; else if (d_next > 32767) d_next = 32767; delta = (d_next - d_prev) >> 2; output_buffer_data[0] = d_prev; output_buffer_data[2] = output_buffer_data[0] + delta; output_buffer_data[4] = output_buffer_data[2] + delta; output_buffer_data[6] = output_buffer_data[4] + delta; output_buffer_data[1] = output_buffer_data[0]; output_buffer_data[3] = output_buffer_data[2]; output_buffer_data[5] = output_buffer_data[4]; output_buffer_data[7] = output_buffer_data[6]; d_prev = d_next; for (i=1 ; i 32767) d_next = 32767; delta = (d_next - d_prev)>>2; output_buffer_data[i*8] = d_prev; output_buffer_data[i*8+2] = output_buffer_data[i*8] + delta; output_buffer_data[i*8+4] = output_buffer_data[i*8+2] + delta; output_buffer_data[i*8+6] = output_buffer_data[i*8+4] + delta; output_buffer_data[i*8+1] = output_buffer_data[i*8]; output_buffer_data[i*8+3] = output_buffer_data[i*8+2]; output_buffer_data[i*8+5] = output_buffer_data[i*8+4]; output_buffer_data[i*8+7] = output_buffer_data[i*8+6]; d_prev = d_next; } last_sample = d_prev; // an essentially non-blocking write() UMSAudioDevice_write(audio_device, audio_env, &output_buffer, output_buffer_samples, &samplepairs_written); // simulate a blocking write() with usleep() UMSAudioDevice_write_buff_used(audio_device, audio_env, &samplepairs_en_route); if (samplepairs_en_route > samplepair_latency) usleep((int) ((samplepairs_en_route - samplepair_latency) * usecs_per_samplepair)); } void sound_uninit() { UMSAudioDevice_play_remaining_data(audio_device, audio_env, TRUE); UMSAudioDevice_stop(audio_device, audio_env); UMSAudioDevice_close(audio_device, audio_env); } char *newpaths[] = { "bin", "dt/bin", "speech/speech_reco/bin", "Demos/speech_reco/bin", "Demos/tts/bin" }; char *newlibpaths[] = { "lib", "speech/speech_reco/lib", "Demos/tts/lib" }; void run_ums(void) { char *path, *u; int i; if (!getenv("SOMBASE")) putenv("SOMBASE=/usr/lpp/som"); fprintf(stderr, "SOMBASE=%s\n", getenv("SOMBASE")); if (!getenv("UMSDIR")) putenv("UMSDIR=/usr/lpp/UMS"); fprintf(stderr, "UMSDIR=%s\n", getenv("UMSDIR")); sprintf(str, "PATH="); path = getenv("PATH"); if (!path || *path==0) path="."; strcat(str, path); for (i=0 ; i<5 ; i++) { sprintf(str+512, "%s/%s", getenv("UMSDIR"), newpaths[i]); fprintf(stderr, "str+512=[%s]\n", str+512); if (!strstr(path, str+512)) { strcat(str, ":"); strcat(str, str+512); fprintf(stderr, "str=[%s]\n", str); } } putenv(str); fprintf(stderr, "PATH=%s\n", getenv("PATH")); sprintf(str, "LIBPATH="); path = getenv("LIBPATH"); if (!path || *path==0) path="."; fprintf(stderr, "[[%s]]\n", path); strcat(str, path); if (!strstr(path, "/usr/lib")) strcat(str, ":/usr/lib"); sprintf(str+512, "%s/lib", getenv("SOMBASE")); if (!strstr(path, str+512)) { strcat(str, ":"); strcat(str, str+512); } for (i=0 ; i<3 ; i++) { sprintf(str+512, "%s/%s", getenv("UMSDIR"), newlibpaths[i]); if (!strstr(path, str+512)) { strcat(str, ":"); strcat(str, str+512); } } putenv(str); fprintf(stderr, "LIBPATH=%s\n", getenv("LIBPATH")); sprintf(str, "NLSPATH="); path = getenv("NLSPATH"); if (!path || *path == 0) path="."; strcat(str, path); sprintf(str+512, "%s/msg/%%N", getenv("SOMBASE")); if (!strstr(path, str+512)) { strcat(str, ":"); strcat(str, str+512); } putenv(str); fprintf(stderr, "NLSPATH=%s\n", getenv("NLSPATH")); sprintf(str, "SOMIR="); path = getenv("SOMIR"); if (!path || *path == 0) path="."; strcat(str, path); sprintf(str+512, "%s/etc/UMS.ir", getenv("UMSDIR")); if (!strstr(path, str+512)) { strcat(str, ":"); strcat(str, str+512); } sprintf(str+512, "%s/etc/som.ir", getenv("UMSDIR")); if (!strstr(path, str+512)) { strcat(str, ":"); strcat(str, str+512); } putenv(str); fprintf(stderr, "SOMIR=%s\n", getenv("SOMIR")); putenv("MALLOCTYPE="); } int sound_init() { UMSAudioDeviceMClass audio_device_class; char *alias; long flags; UMSAudioDeviceMClass_ErrorCode audio_device_class_error; char *error_string; char *audio_formats_alias; char *audio_inputs_alias; char *audio_outputs_alias; int bits_per_sample; long out_rate; int channels; long left_gain; long right_gain; char *sl; // run_ums(); audio_env = somGetGlobalEnvironment(); audio_device_class = UMSAudioDeviceNewClass(UMSAudioDevice_MajorVersion, UMSAudioDevice_MinorVersion); if (audio_device_class == NULL) { fprintf(stderr, "sound driver: Can't create AudioDeviceMClass metaclass\n"); return 0; } alias = "Audio"; flags = UMSAudioDevice_BlockingIO; audio_device = UMSAudioDeviceMClass_make_by_alias(audio_device_class, audio_env, alias, "PLAY", flags, &audio_device_class_error, &error_string, &audio_formats_alias, &audio_inputs_alias, &audio_outputs_alias); if (audio_device == NULL) { fprintf(stderr, "sound driver : Can't create audio device object\n"); return 0; } channels = 2; bits_per_sample = 16; UMSAudioDevice_set_sample_rate(audio_device, audio_env, 44100, &out_rate); UMSAudioDevice_set_bits_per_sample(audio_device, audio_env, bits_per_sample); UMSAudioDevice_set_number_of_channels(audio_device, audio_env, channels); if (out_rate != 44100) { fprintf(stderr, "sound driver : Doesn't support 44.1kHz\n"); return 0; } UMSAudioDevice_set_audio_format_type(audio_device, audio_env, "PCM"); UMSAudioDevice_set_byte_order(audio_device, audio_env, "MSB"); UMSAudioDevice_set_number_format(audio_device, audio_env, "TWOS_COMPLEMENT"); UMSAudioDevice_set_volume(audio_device, audio_env, 100); UMSAudioDevice_set_balance(audio_device, audio_env, 0); output_buffer_samples = BUF_SIZE * 4; UMSAudioDevice_set_time_format(audio_device, audio_env, UMSAudioTypes_Samples); left_gain = right_gain = 100; UMSAudioDevice_enable_output(audio_device, audio_env, "INTERNAL_SPEAKER", &left_gain, &right_gain); left_gain = right_gain = 100; UMSAudioDevice_enable_output(audio_device, audio_env, "LINE_OUT", &left_gain, &right_gain); UMSAudioDevice_initialize(audio_device, audio_env); UMSAudioDevice_start(audio_device, audio_env); output_buffer._maximum = BUF_SIZE*8*2; output_buffer_data = (short *) malloc(output_buffer._maximum); output_buffer._buffer = (octet *) output_buffer_data; usecs_per_samplepair = 1000000.0 / out_rate; samplepair_latency = 1500; sl = getenv("SAMPLEPAIR_LATENCY"); if (sl) samplepair_latency = atoi(sl); last_sample = 0; return 1; }