$NetBSD: patch-ab,v 1.2 2000/12/18 00:03:38 wiz Exp $ --- sys/NetBSD/audio.c.orig Sun May 23 10:29:13 1999 +++ sys/NetBSD/audio.c Sun May 23 10:55:39 1999 @@ -0,0 +1,298 @@ +/* + * NetBSD サウンド処理 + */ + +/* + * Copyright (c) 1994 Kazuhiko Ishii. + * Copyright (c) 1995 Masanobu Saitoh. + * + * 本ソフトウェアのソースやバイナリを再配布する場合は、次の条件を遵守して + * 下さい。 + * + * 1. 本ソフトウェアを入手した方には、X11版 Emi Clock の使用権と、第三者 + * への再配布権が認められます。ただし、再配布に関しては、入手時のオリ + * ジナルのまま改変せずに行うことが条件です。 + * 2. 本ソフトウェアの一部または全部を著作権者に無断で改変して配布するこ + * とはできません。 + * 3. 本ソフトウェアの一部または全部を著作権者に無断で二次利用することは + * できません。 + * 4. 本ソフトウェアをシステムにバンドルしたり、システムの追加パッケージ + * として第三者に再配布したりする場合は、事前に著作権者に許可が必要で + * す。 + * 5. 本ソフトウェアを商用に使用する場合(金銭的利益を得る場合)は、事前に + * 著作権者に許可が必要です。この場合、基本的に有償となります。 + * 6. 本ソフトウェアを利用することによって発生したいかなる損害も、著作権 + * 者は負わないものとします。これに合意できない場合は、使用権がないも + * のとします。 + * 7. “Emi Clock”の商標および本ソフトウェアの画像やデザインに関する著作 + * 権は、Motosoft こと“本 俊也”氏が有します。 + * 8. “Emi Clock”の商標および画像やデザインは、X11版 Emi Clock 開発のた + * め、Motosoft より“古場 正行”へ個人的にライセンス供与されてます。 + * 第三者へ二次ライセンス供与することは認められておりません。 + * 9. Motosoft と古場に無断で、本ソフトウェアの画像データを二次利用するこ + * とを禁止します。 + * 10. ここに記述した以外の権利については、日本国の著作権法によるものとし + * ます。 + */ + + +/* 定数 */ +#define HAS_SOUND_CODE /* サウンド関係のコードは有効! */ + +/* RCS ID */ +rcsId(audioId, "Id: audio.c,v 1.5 1994/05/31 06:28:21 masa-k Rel ") + +static int S_AuFileHeader(); +static void S_PlayInterval(); + +static int AudioDevice; +static audio_info_t AudioSaveConfig; +static int SoundLeft; +static int SoundPlayed; +static int SoundTimeBytes; +static char *SoundBufPtr; +static char *SoundTmpBuffer = NULL; +static struct timeval SoundStart; + +/* + * サウンド環境の初期化 + */ +static void +S_SoundEnvInit() +{ + /* 何もしない */ +} + + +/* + * サウンドデバイスの存在判定 + */ +static Boolean +S_IsSoundAvailable() +{ + struct stat st; + + /* オーディオI/Fのチェック */ + if (stat(AUDIO_DEVICE, &st) < 0) + return False; + if (!S_ISCHR(st.st_mode)) + return False; + + return True; +} + + +/* + * サウンド再生 + */ +static int +S_PlaySound(filename) +char *filename; +{ + SoundCacheBuffer localCache; + int ret; + + if ((ret = S_CacheSound(filename, &localCache)) != SOUND_NO_ERROR) + return ret; + SoundTmpBuffer = localCache.soundCacheBuffer; + if ((ret = S_PlayCacheSound(&localCache)) != SOUND_NO_ERROR) { + S_FreeCacheSound(&localCache); + return ret; + } + return SOUND_NO_ERROR; +} + + +/* + * サウンドのキャッシュ化可能/不可能判定 + */ +static Boolean +S_IsSoundCacheAvailable() +{ + return True; +} + + +/* + * サウンドのキャッシュ化 + */ +static int +S_CacheSound(filename, cacheBufferPtr) +char *filename; +SoundCacheBuffer *cacheBufferPtr; +{ + int soundFile; + + if ((soundFile = open(filename, O_RDONLY)) < 0) + return SOUND_OPEN_ERROR; + AUDIO_INITINFO(&(cacheBufferPtr->soundBParam)); + if ((cacheBufferPtr->soundLength = S_AuFileHeader(soundFile, + &(cacheBufferPtr->soundBParam))) < 0) { + close(soundFile); + return SOUND_FILE_INVALID; + } + cacheBufferPtr->soundCacheBuffer = + (char *)XtMalloc(cacheBufferPtr->soundLength); + read(soundFile, cacheBufferPtr->soundCacheBuffer, + cacheBufferPtr->soundLength); + close(soundFile); + return SOUND_NO_ERROR; +} + + +/* + * キャッシュ化されたサウンドの再生 + */ +static int +S_PlayCacheSound(cacheBufferPtr) +SoundCacheBuffer *cacheBufferPtr; +{ + int tmpfd; + if ((tmpfd = open(AUDIO_DEVICE, O_WRONLY)) < 0) { + if (errno == EBUSY) + return SOUND_DEVICE_BUSY; + return SOUND_DEVICE_ERROR; + } + AudioDevice = tmpfd; + ioctl(AudioDevice, AUDIO_GETINFO, &AudioSaveConfig); + /* オーディオファイルに合わせてデバイスをセットする + デバイス未サポートの形式のオーディオファイルはエラー */ + if (ioctl(AudioDevice, AUDIO_SETINFO, + &(cacheBufferPtr->soundBParam)) < 0) { + close(AudioDevice); + return SOUND_DEVICE_ERROR; + } + /* オーディオデバイスをノンブロッキングモードに設定 */ + fcntl(AudioDevice, F_SETFL, fcntl(AudioDevice, F_GETFL, 0) | O_NDELAY); + SoundBufPtr = cacheBufferPtr->soundCacheBuffer; + SoundLeft = cacheBufferPtr->soundLength; + SoundPlayed = 0; + SoundTimeBytes = (cacheBufferPtr->soundBParam.play.precision / 8) * + cacheBufferPtr->soundBParam.play.channels * + cacheBufferPtr->soundBParam.play.sample_rate; + signal(SIGALRM, S_PlayInterval); + gettimeofday(&SoundStart, NULL); + S_PlayInterval(); + return SOUND_NO_ERROR; +} + + +/* + * キャッシュ化されたサウンドの開放 + */ +static void +S_FreeCacheSound(cacheBufferPtr) +SoundCacheBuffer *cacheBufferPtr; +{ + XtFree(cacheBufferPtr->soundCacheBuffer); +} + + +/* + * サウンド環境の後始末 + */ +static void +S_SoundEnvDispose() +{ + /* 何もしない */ +} + +/* + * SIGALRMで呼ばれる関数 + */ +static void +S_PlayInterval() +{ + int nbytes, timer; + struct itimerval t; + struct timeval now; + + if (SoundLeft > 0) { + if ((nbytes = write(AudioDevice, SoundBufPtr, SoundLeft)) > 0) { + SoundPlayed += nbytes; + SoundLeft -= nbytes; + SoundBufPtr += nbytes; + timer = ((double)SoundPlayed / (double)SoundTimeBytes) + * 1000000; + gettimeofday(&now, NULL); + timer -= (now.tv_sec - SoundStart.tv_sec) * 1000000 + + now.tv_usec - SoundStart.tv_usec; + if (timer <= 0) + timer = 1; + } else { + timer = 1; + if (nbytes < 0 && errno != EBUSY) + SoundLeft = 0; + } + t.it_interval.tv_sec = 0; + t.it_interval.tv_usec = 0; + t.it_value.tv_sec = timer / 1000000; + t.it_value.tv_usec = timer % 1000000; + setitimer(ITIMER_REAL, &t, NULL); + } else { + if (close(AudioDevice) == -1) + perror("nazo\n"); + if (SoundTmpBuffer != NULL) { + XtFree(SoundTmpBuffer); + SoundTmpBuffer = NULL; + } + signal(SIGALRM, SIG_IGN); + } +} + +#if BYTE_ORDER == LITTLE_ENDIAN +# define BSWAP32(x) x = bswap32(x) +#endif +#if BYTE_ORDER == BIG_ENDIAN +# define BSWAP32(x) +#endif +#if BYTE_ORDER == PDP_ENDIAN +# error lose. +#endif + +/* + * .auファイルのヘッダ情報を返す関数 + * ファイル位置はデータ部の先頭にセットされる。 + */ +static int +S_AuFileHeader(file, audio) +int file; +audio_info_t *audio; +{ + static int formattable[] = { + 0, 0, /* Not defined */ + AUDIO_ENCODING_ULAW, 8, /* 8-bit ISDN u-law */ + AUDIO_ENCODING_LINEAR, 8, /* 8-bit linear PCM */ + AUDIO_ENCODING_LINEAR, 16, /* 16-bit linear PCM */ + AUDIO_ENCODING_LINEAR, 24, /* 24-bit linear PCM */ + AUDIO_ENCODING_LINEAR, 32 /* 32-bit linear PCM */ + }; + + long magic, pos, size, format, rate, chan; + struct stat st; + + read(file, &magic, sizeof(long)); + BSWAP32(magic); + if (magic != AUDIOMAGICNUMBER) + return -1; + read(file, &pos, sizeof(long)); + BSWAP32(pos); + read(file, &size, sizeof(long)); + BSWAP32(size); + read(file, &format, sizeof(long)); + BSWAP32(format); + read(file, &rate, sizeof(long)); + BSWAP32(rate); + read(file, &chan, sizeof(long)); + BSWAP32(chan); + if (format < 1 || format > 5) + return -1; + format = format * 2; + audio->play.encoding = formattable[format]; + audio->play.precision = formattable[format + 1]; + audio->play.sample_rate = rate; + audio->play.channels = chan; + lseek(file, pos, SEEK_SET); + fstat(file, &st); + return st.st_size - pos; +}