long audio_poll(snd_type snd) { oss_info dp = get_oss_info(snd); /* Note that this returns frames while audio_write returns bytes */ if (snd->write_flag == SND_READ) return (dp->len / snd_bytes_per_frame(snd)); else return ((dp->buffersize - dp->len) / snd_bytes_per_frame(snd)); }
void snd_print_info(snd_type snd) { if (snd->device == SND_DEVICE_AUDIO) { if (snd->write_flag == SND_READ) { printf("audio input"); } else { printf("audio output"); } } else if (snd->device == SND_DEVICE_MEM) { if (snd->write_flag == SND_READ) { printf("from memory buffer"); } else { printf("to memory buffer"); } } else { printf("header %s", header_to_string(snd->u.file.header)); } printf(", channels %d, mode %s, bits %d, srate %g", snd->format.channels, snd_mode_to_string(snd->format.mode), snd->format.bits, snd->format.srate); if (snd->device == SND_DEVICE_MEM) { if (snd->write_flag == SND_READ) { printf("length %d\n", snd->u.mem.buffer_len); } else { printf("length %d\n", snd->u.mem.buffer_max); } } else if (snd->device == SND_DEVICE_FILE && snd->write_flag == SND_READ) { printf(", length %d\n", (snd->u.file.end_offset - snd->u.file.byte_offset) / snd_bytes_per_frame(snd)); } else printf("\n"); }
void *audio_descr_build(snd_type snd) { int i, j; buffer_state *bufstate; double bufsize_in_frames; bufstate = (buffer_state *) snd_alloc(sizeof(buffer_state)); if (snd->u.audio.protocol == SND_REALTIME){ bufstate->numofbuffers = 3; } else { if (snd->u.audio.protocol != SND_COMPUTEAHEAD) snd_fail("Invalid protocol identifier. COMPUTEAHEAD method used instead"); bufstate->numofbuffers = 2; } if (NULL == (bufstate->whdr = (LPWAVEHDR)snd_alloc(bufstate->numofbuffers * sizeof(WAVEHDR)))){ snd_fail("Not enough memory, or similar"); snd_free(bufstate); return NULL; } bufsize_in_frames = max(Audio_out_min_buffersize, snd->format.srate * snd->u.audio.latency); if (bufsize_in_frames > snd->format.srate * snd->u.audio.latency) snd->u.audio.latency = bufsize_in_frames / snd->format.srate; for (i=0; i<bufstate->numofbuffers; i++){ bufstate->whdr[i].dwBufferLength = (long)(bufsize_in_frames + 0.5) * snd_bytes_per_frame(snd); if (NULL == (bufstate->whdr[i].lpData = (char *) snd_alloc(bufstate->whdr[i].dwBufferLength))){ snd_fail("Not enough memory, or similar"); for (j=0; j<i-1; j++){ snd_free(bufstate->whdr[j].lpData); } snd_free(bufstate); return NULL; } bufstate->whdr[i].dwUser = bufstate->whdr[i].dwLoops = 0; //idrk, what's that bufstate->whdr[i].dwFlags = WHDR_DONE; } bufstate->pollee = 0; bufstate->posinbuffer = 0; if (snd->u.audio.protocol == SND_REALTIME){ bufstate->sync_buffer = 0; bufstate->prev_time = timeGetTime(); bufstate->sync_time = bufstate->prev_time - (long)(2 * 1000 * snd->u.audio.latency + .5); } return (void *) bufstate; }
MMRESULT win_wave_open(snd_type snd, UINT devtoopen, HWAVE *hptr) { WAVEFORMATEX wfmt; int bperf; switch (snd->format.mode) { case SND_MODE_UNKNOWN: case SND_MODE_PCM: /* note: Windows uses signed PCM (PCM) for 16-bit data, and * unsigned PCM (UPCM) for 8-bit data */ if (snd->format.bits != 8) { wfmt.wFormatTag = WAVE_FORMAT_PCM; break; } else return WAVERR_BADFORMAT; case SND_MODE_ADPCM: case SND_MODE_ALAW: case SND_MODE_ULAW: case SND_MODE_FLOAT: case SND_MODE_UPCM: if (snd->format.bits == 8) { wfmt.wFormatTag = WAVE_FORMAT_PCM; break; } else return(WAVERR_BADFORMAT); default: return(MMSYSERR_INVALPARAM); } wfmt.nChannels = (unsigned short) snd->format.channels; wfmt.nSamplesPerSec = (long) (snd->format.srate + 0.5); bperf = snd_bytes_per_frame(snd); wfmt.nAvgBytesPerSec = (long) (bperf * snd->format.srate + 0.5); wfmt.nBlockAlign = (unsigned short) bperf; wfmt.wBitsPerSample = (unsigned short) snd->format.bits; wfmt.cbSize = 0; if (snd->write_flag != SND_READ) { /* Under Windows2000 on an IBM A21p Thinkpad, waveOutOpen will CRASH (!) if snd->format.srate is 110250, but it actually worked with 4000, and it worked with 96000, so I will assume sample rates above 96000 are bad. -RBD 24Jul02 */ if (wfmt.nSamplesPerSec > 96000) { return WAVERR_BADFORMAT; } /* otherwise, we're ready to open the device */ return waveOutOpen((LPHWAVEOUT) hptr, devtoopen, &wfmt, 0L, 0L, (DWORD) CALLBACK_NULL); } else { return waveInOpen((LPHWAVEIN) hptr, devtoopen, &wfmt, 0L, 0L, (DWORD) CALLBACK_NULL); } }
long audio_write(snd_type snd, void *buffer, long length_in_bytes) { oss_info dp = get_oss_info(snd); pthread_mutex_lock(&dp->mutex); if (dp->len + length_in_bytes > dp->buffersize) length_in_bytes = dp->buffersize - dp->len; copy_to_wrap_buffer(dp, buffer, length_in_bytes); pthread_mutex_unlock(&dp->mutex); return (length_in_bytes / snd_bytes_per_frame(snd)); }
/* * We want to write as soon as space is available so that * a full sound buffer can be queued up for output. This * may require transferring only part of buf, so we keep * track of progress and output whenever space is available. */ void write_to_audio(snd_type player, void *buf, long buflen) { long rslt; while (buflen) { /* this loop is a busy-wait loop! */ rslt = snd_poll(player); /* wait for buffer space */ rslt = min(rslt, buflen); if (rslt) { snd_write(player, buf, rslt); buf = (void *) ((char *) buf + (rslt * snd_bytes_per_frame(player))); buflen -= rslt; } } }
long audio_read(snd_type snd, void *buffer, long length_in_bytes) { oss_info dp = get_oss_info(snd); if (length_in_bytes <= 0) return 0; pthread_mutex_lock(&dp->mutex); if (length_in_bytes > dp->len) length_in_bytes = dp->len; copy_from_wrap_buffer(dp, buffer, length_in_bytes); pthread_mutex_unlock(&dp->mutex); return (length_in_bytes / snd_bytes_per_frame(snd)); }
int audio_open(snd_type snd, long *flags) { int format; int channels; int rate; oss_info dp; const char *device = "/dev/dsp"; pthread_t thread; snd->u.audio.descriptor = (oss_info) malloc(sizeof(oss_info_struct)); dp = get_oss_info(snd); if (snd->u.audio.devicename[0] != 0) device = snd->u.audio.devicename; if (snd->write_flag == SND_READ) { /* open audio input */ /* Open /dev/dsp */ dp->audio_fd = open(device, O_RDONLY, 0); if (dp->audio_fd == -1) return !SND_SUCCESS; } else { /* open audio output */ /* Open /dev/dsp */ dp->audio_fd = open(device, O_WRONLY, 0); if (dp->audio_fd == -1) return !SND_SUCCESS; } /* Set format to signed 16-bit little-endian */ format = AFMT_S16_LE; if (ioctl(dp->audio_fd, SNDCTL_DSP_SETFMT, &format) == -1) return !SND_SUCCESS; if (format != AFMT_S16_LE) /* this format is not supported */ return !SND_SUCCESS; /* Set number of channels */ channels = snd->format.channels; if (ioctl(dp->audio_fd, SNDCTL_DSP_CHANNELS, &channels) == -1) return !SND_SUCCESS; if (channels != snd->format.channels) return !SND_SUCCESS; /* Set sampling rate. Must set sampling rate AFTER setting number of channels. */ rate = (int)(snd->format.srate + 0.5); if (ioctl(dp->audio_fd, SNDCTL_DSP_SPEED, &rate) == -1) return !SND_SUCCESS; if (rate - (int)(snd->format.srate + 0.5) > 100 || rate - (int)(snd->format.srate + 0.5) < -100) return !SND_SUCCESS; /* finish initialization and start the thread */ if (snd->write_flag == SND_READ) { /* always buffer 10 seconds of audio for reading (no reason not to for this implementation */ dp->buffersize = rate * 10.0 * snd_bytes_per_frame(snd); } else { if (snd->u.audio.latency > 0.0) dp->buffersize = rate * snd->u.audio.latency * snd_bytes_per_frame(snd); else dp->buffersize = rate * 1.0 * snd_bytes_per_frame(snd); } dp->buffer = malloc(dp->buffersize); dp->start = 0; dp->len = 0; dp->error_count = 0; dp->stop_flag = 0; pthread_mutex_init (&dp->mutex, 0); if (snd->write_flag == SND_READ) { if (0 != pthread_create(&dp->thread, NULL, record_thread, (void *)dp)) return !SND_SUCCESS; } else { if (0 != pthread_create(&dp->thread, NULL, playback_thread, (void *)dp)) return !SND_SUCCESS; } return SND_SUCCESS; }
long audio_poll(snd_type snd) { long availtemp; buffer_state *cur = ((buffer_state*) snd->u.audio.descriptor); LPWAVEHDR whdrs = cur->whdr; int i, test = 0; int numbuf = cur->numofbuffers; for (i=0; i<numbuf; i++){ if (whdrs[i].dwFlags & WHDR_DONE){ test++; } } if (snd->u.audio.protocol == SND_REALTIME) { int last_buf, k; if (test < numbuf) { /* there is at least one buffer being processed by the * device (not "done") */ if (test) { /* there is at last one buffer done */ long bufferbytes; if (whdrs[cur->sync_buffer].dwFlags & WHDR_DONE){ k = (cur->sync_buffer + 1) % numbuf; while (k != cur->sync_buffer){ if (!(whdrs[k].dwFlags & WHDR_DONE)){ cur->sync_buffer = k; break; } k = (k + 1) % numbuf; } cur->sync_time = cur->prev_time; } else cur->prev_time = timeGetTime(); availtemp = (long) (((double)(cur->prev_time - cur->sync_time) * max_srate_dev / 1000 /*+ 2 * snd->u.audio.latency*/) * snd->format.srate); last_buf = (cur->sync_buffer + numbuf - 1) % numbuf; while (last_buf != cur->pollee) { availtemp += whdrs[last_buf].dwBufferLength; last_buf = (last_buf + numbuf - 1) % numbuf; } bufferbytes = test * (long) whdrs[0].dwBufferLength; if (bufferbytes < availtemp * snd_bytes_per_frame(snd)) { return bufferbytes / snd_bytes_per_frame(snd); } else { return availtemp; } } else { /* all buffer already passed to the device, it * should happen only just because we "overestimate" * the sample-rate */ cur->prev_time = timeGetTime(); cur->sync_time = cur->prev_time; return 0; } } else { //all buffers are done cur->prev_time = timeGetTime(); cur->sync_time = cur->prev_time; return ((numbuf - 1) * whdrs[0].dwBufferLength) / snd_bytes_per_frame(snd); } } else { /* protocol SND_COPMUTEAHEAD */ /* here is suppose that all buffer have the same length * (otherwise, sg like "for(i=0;i<numbuf;i++) * available+=whdrs[i].dwBufferLength" should be used) */ return (test * whdrs[0].dwBufferLength - cur->posinbuffer) / snd_bytes_per_frame(snd); } }
int audio_open(snd_node *n, long *f) { buffer_state *data = (buffer_state *)malloc(sizeof(buffer_state)); n->u.audio.descriptor = (void *)data; OSErr err; Fixed sampleRateFixed; data->frameSize = snd_bytes_per_frame(n); data->bufferSize = (int) (n->format.srate * (double)data->frameSize); if (n->u.audio.latency > 0.0) data->bufferSize = (int)(n->format.srate * n->u.audio.latency) * data->frameSize; /* Calculate sample rate as an unsigned fixed-point number */ if (n->format.srate > 65535.0 || n->format.srate < 1.0) sampleRateFixed = 0xAC440000; /* Fixed for 44100 */ else { unsigned short numerator = (unsigned short)n->format.srate; unsigned short denominator = (unsigned short)(65536.0*(n->format.srate - numerator)); sampleRateFixed = (numerator << 16) | denominator; } /* Open device for recording or playback, depending on mode selected */ if (n->write_flag == SND_READ) { /* recording */ short gainControl = 0; /* off */ short numChannels = n->format.channels; short continuousRecording = 1; /* on */ short playthroughVolume = 0; /* off */ OSType quality = 'cd '; short sampleSize = 16; short twos = 0; /* i.e. signed */ OSType compression = 'NONE'; SoundInfoList infoList; int len, i, x, y, z; short selected = 0; char *device; char *input; char **buffer; char oneInput[256]; char *deviceData; data->recording = 1; len = strlen(n->u.audio.devicename); device = new char[len+1]; input = new char[len+1]; strcpy(device, n->u.audio.devicename); input[0] = 0; for(i=0; i<len; i++) { if (device[i] == '\n') { device[i] = 0; strcpy(input, &device[i+1]); i = len; } } err = SPBOpenDevice(c2pstr(device), siWritePermission, &data->refnum); if (err) return !SND_SUCCESS; SPBGetDeviceInfo (data->refnum, siInputAvailable, &infoList); SPBGetDeviceInfo (data->refnum, siInputSourceNames, &buffer); deviceData = buffer[0] + 2; for(int x=0; x<infoList.count; x++) { int y = *deviceData++; z = 0; while(y) { oneInput[z++] = *deviceData++; y--; } oneInput[z] = 0; if (!strcmp(oneInput, input)) selected = x; } selected++; SPBSetDeviceInfo (data->refnum, siInputSource, &selected); SPBSetDeviceInfo(data->refnum, 'qual', &quality); SPBSetDeviceInfo(data->refnum, 'agc ', &gainControl); SPBSetDeviceInfo(data->refnum, 'srat', &sampleRateFixed); SPBSetDeviceInfo(data->refnum, 'plth', &playthroughVolume); err = SPBSetDeviceInfo(data->refnum, 'ssiz', &sampleSize); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'chan', &numChannels); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'cont', &continuousRecording); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'twos', &twos); if (err) return !SND_SUCCESS; err = SPBSetDeviceInfo(data->refnum, 'comp', &compression); if (err) return !SND_SUCCESS; data->recBuffer = (char *)malloc(data->bufferSize); data->recqStart = 0; data->recqEnd = 0; data->starved = 0; data->params.inRefNum = data->refnum; data->params.count = 0; /* data->bufferSize; /* bytes to record */ data->params.milliseconds = 0; /* param will be ignored; use count */ data->params.bufferLength = 0; /* ignore buffer */ data->params.bufferPtr = NULL; /* ignore buffer */ data->params.completionRoutine = NULL; data->params.userLong = (long)data; data->params.unused1 = 0; data->params.interruptRoutine = NewSIInterruptUPP(recordingCallback); err = SPBRecord(&data->params, true); if (err) return !SND_SUCCESS; } else { /* playback */ data->recording = 0; data->chan = NULL; //////////////////////// err = SndNewChannel(&data->chan, sampledSynth, 0, NULL); if (err) return !SND_SUCCESS; data->buffer = (char *)malloc(data->bufferSize); data->nextBufferSize = data->bufferSize * 3; data->nextBuffer = (char *)malloc(data->nextBufferSize); if (!data->buffer || !data->nextBuffer) return !SND_SUCCESS; data->chan->callBack = NewSndCallBackUPP(playbackCallback); data->header.samplePtr = data->buffer; data->header.numChannels = n->format.channels; data->header.sampleRate = sampleRateFixed; data->header.loopStart = 0; data->header.loopEnd = 0; data->header.encode = cmpSH; data->header.baseFrequency = kMiddleC; // data->header.AIFFSampleRate = 0; -- this parameter is unused data->header.markerChunk = NULL; data->header.format = kSoundNotCompressed; data->header.futureUse2 = NULL; data->header.stateVars = NULL; data->header.leftOverSamples = NULL; data->header.compressionID = 0; data->header.packetSize = 0; data->header.snthID = 0; data->header.sampleSize = 16; data->header.sampleArea[0] = 0; data->playCmd.cmd = bufferCmd; data->playCmd.param1 = 0; //unused data->playCmd.param2 = (long)&data->header; data->callCmd.cmd = callBackCmd; data->callCmd.param1 = 0; data->callCmd.param2 = (long)data; data->curBuffer = 0; data->curSize = 0; data->firstTime = 1; data->finished = 0; data->busy = 0; data->flushing = 0; } return SND_SUCCESS; }
int main(int argc, char *argv[]) { char *fromfile = NULL; char *tofile = NULL; int i; long flags = 0; long frames; long len; long checksum = 0; long count = 0; int format = SND_HEAD_AIFF; int mode = SND_MODE_PCM; int channels = 1; int bits = 16; double srate = 44100.0; snd_node from_snd, to_snd; char from_buf[MAXLEN]; char to_buf[MAXLEN]; long frames_from_len; long frames_to_len; long from_len = 0; long to_len = 0; for (i = 1; i < argc; i++) { if (*(argv[i]) != '-') { if (!fromfile) fromfile = argv[i]; else if (!tofile) tofile = argv[i]; else { printf("%s: don't know what to do with 3rd file\n", argv[i]); return 1; } } else { char *flag = argv[i] + 1; if (*flag == '?') { printf("convert -- sound file conversion utility\n\n"); printf("usage: convert fromfile tofile -flag1 -flag2 ...\n"); printf(" -fa -- AIFF file format\n"); printf(" -fi -- IRCAM file format\n"); printf(" -fn -- NeXT/Sun file format\n"); printf(" -fw -- Wave file format\n"); printf(" -ep -- PCM\n"); printf(" -em -- u-Law\n"); printf(" -ef -- float\n"); printf(" -eu -- unsigned PCM\n"); printf(" -b1 -- 8-bit\n"); printf(" -b2 -- 16-bit\n"); printf(" -b4 -- 32-bit\n"); printf(" -c1 -- 1 channel, etc.\n"); printf("use 'ada' to get audio input or output\n"); } else if (*flag == 'f') { switch (flag[1]) { case 'a': format = SND_HEAD_AIFF; break; case 'i': format = SND_HEAD_IRCAM; break; case 'n': format = SND_HEAD_NEXT; break; case 'w': format = SND_HEAD_WAVE; break; default: printf("flag %s ignored\n", argv[i]); break; } } else if (*flag == 'e') { switch (flag[1]) { case 'p': mode = SND_MODE_PCM; break; case 'm': mode = SND_MODE_ULAW; break; case 'f': mode = SND_MODE_FLOAT; break; case 'u': mode = SND_MODE_UPCM; break; default: printf("flag %s ignored\n", argv[i]); break; } } else if (*flag == 'b') { switch (flag[1]) { case '1': bits = 8; break; case '2': bits = 16; break; case '4': bits = 32; break; default: printf("flag %s ignored\n", argv[i]); break; } } else if (*flag == 'r') { switch (flag[1]) { case '4': srate = 44100.0; break; case '2': srate = 22050.0; break; case '1': srate = 11025.0; break; case '8': srate = 8000.0; break; default: printf("flag %s ignored\n", argv[i]); break; } } else if (*flag == 'c') { channels = atoi(flag+1); if (channels < 1 || channels > 16) { channels = 1; printf("flag %s ignored, using 1 channel\n", argv[i]); } } } } if (!tofile) { printf("2 files not found, use -? for help\n"); return 1; } from_snd.device = SND_DEVICE_FILE; from_snd.write_flag = SND_READ; from_snd.u.file.byte_offset = 0; from_snd.format.channels = channels; from_snd.format.mode = mode; from_snd.format.bits = bits; from_snd.format.srate = srate; if (strcmp(fromfile, "ada") == 0) { from_snd.device = SND_DEVICE_AUDIO; from_snd.u.audio.protocol = SND_COMPUTEAHEAD; from_snd.u.audio.latency = 1.0; from_snd.u.audio.granularity = 0.1; strcpy(from_snd.u.file.filename, ""); } else { strcpy(from_snd.u.file.filename, fromfile); } if (snd_open(&from_snd, &flags) != SND_SUCCESS) { printf("error opening %s for input\n", fromfile); exit(1); } printf("Opened %s for input: ", from_snd.u.file.filename); snd_print_info(&from_snd); to_snd.device = SND_DEVICE_FILE; to_snd.write_flag = SND_WRITE; to_snd.format.channels = channels; to_snd.format.mode = mode; to_snd.format.bits = bits; to_snd.format.srate = from_snd.format.srate; to_snd.u.file.header = format; /* header format, e.g. AIFF */ if (to_snd.u.file.header == SND_HEAD_WAVE && to_snd.format.mode == SND_MODE_PCM && to_snd.format.bits == 8) to_snd.format.mode = SND_MODE_UPCM; if (strcmp(tofile, "ada") == 0) { to_snd.device = SND_DEVICE_AUDIO; to_snd.u.audio.protocol = SND_COMPUTEAHEAD; to_snd.u.audio.latency = 0.0; to_snd.u.audio.granularity = 0.1; strcpy(to_snd.u.audio.interfacename, ""); strcpy(to_snd.u.audio.devicename, ""); } else { strcpy(to_snd.u.file.filename, tofile); } if (snd_open(&to_snd, &flags) != SND_SUCCESS) { printf("error opening %s for output\n", tofile); exit(1); } printf("Opened %s for output: ", to_snd.u.file.filename); snd_print_info(&to_snd); /* figure out how much to convert on each iteration */ /* first, compute how many frames could fit in each buffer */ from_len = MAXLEN / snd_bytes_per_frame(&from_snd); to_len = MAXLEN / snd_bytes_per_frame(&to_snd); /* then compute the minimum of the two frame counts */ frames = min(from_len, to_len); while (1) { /* then convert back from frame counts to byte counts: */ while ((frames_from_len = snd_poll(&from_snd)) <=0); frames_from_len = min(frames_from_len, frames); while ((frames_to_len = snd_poll(&to_snd)) <= 0); frames_to_len = min(frames_to_len, frames); len = min(frames_to_len, frames_from_len); len = snd_read(&from_snd, from_buf, len); if (((from_snd.device == SND_DEVICE_AUDIO) && (count > from_snd.format.srate * 10)) || (!len)) { break; } for (i = 0; i < len * snd_bytes_per_frame(&from_snd); i++) { checksum += from_buf[i]; count++; } len = snd_convert(&to_snd, to_buf, &from_snd, from_buf, len); len = snd_write(&to_snd, to_buf, len); printf("#"); fflush(stdout); } snd_close(&from_snd); if (to_snd.device == SND_DEVICE_AUDIO) { while (snd_flush(&to_snd) != SND_SUCCESS) ; } snd_close(&to_snd); printf("Read %ld frames, checksum = %ld\n", count, checksum); exit(0); }