static int waveout_open(sample_format_t sf) { WAVEFORMATEX format; int rc, i; /* WAVEFORMATEX does not support channels > 2, waveOutWrite() wants little endian signed PCM */ if (sf_get_bigendian(sf) || !sf_get_signed(sf) || sf_get_channels(sf) > 2) { return -OP_ERROR_SAMPLE_FORMAT; } memset(&format, 0, sizeof(format)); format.cbSize = sizeof(format); format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = sf_get_channels(sf); format.nSamplesPerSec = sf_get_rate(sf); format.wBitsPerSample = sf_get_bits(sf); format.nAvgBytesPerSec = sf_get_second_size(sf); format.nBlockAlign = sf_get_frame_size(sf); if ((rc = waveOutOpen(&wave_out, WAVE_MAPPER, &format, 0, 0, CALLBACK_NULL)) != MMSYSERR_NOERROR) { switch (rc) { case MMSYSERR_ALLOCATED: errno = EBUSY; return -OP_ERROR_ERRNO; case MMSYSERR_BADDEVICEID: case MMSYSERR_NODRIVER: errno = ENODEV; return -OP_ERROR_ERRNO; case MMSYSERR_NOMEM: errno = ENOMEM; return -OP_ERROR_ERRNO; case WAVERR_BADFORMAT: return -OP_ERROR_SAMPLE_FORMAT; } return -OP_ERROR_INTERNAL; } /* reset buffers */ for (i = 0; i < buffer_count; i++) { buffers[i].dwFlags = 0; } buffer_idx = 0; buffers_free = buffer_count; waveout_sf = sf; return 0; }
static inline unsigned int buffer_second_size(void) { return sf_get_second_size(buffer_sf); }
static int oss_set_sf(sample_format_t sf) { int tmp, log2_fragment_size, nr_fragments, bytes_per_second; oss_reset(); oss_sf = sf; #ifdef SNDCTL_DSP_CHANNELS tmp = sf_get_channels(oss_sf); if (ioctl(oss_fd, SNDCTL_DSP_CHANNELS, &tmp) == -1) return -1; #else tmp = sf_get_channels(oss_sf) - 1; if (ioctl(oss_fd, SNDCTL_DSP_STEREO, &tmp) == -1) return -1; #endif if (sf_get_bits(oss_sf) == 16) { if (sf_get_signed(oss_sf)) { if (sf_get_bigendian(oss_sf)) { tmp = AFMT_S16_BE; } else { tmp = AFMT_S16_LE; } } else { if (sf_get_bigendian(oss_sf)) { tmp = AFMT_U16_BE; } else { tmp = AFMT_U16_LE; } } } else if (sf_get_bits(oss_sf) == 8) { if (sf_get_signed(oss_sf)) { tmp = AFMT_S8; } else { tmp = AFMT_U8; } } else if (sf_get_bits(oss_sf) == 32 && sf_get_signed(oss_sf)) { if (sf_get_bigendian(oss_sf)) { tmp = AFMT_S32_BE; } else { tmp = AFMT_S32_LE; } } else if (sf_get_bits(oss_sf) == 24 && sf_get_signed(oss_sf) && !sf_get_bigendian(oss_sf)) { tmp = AFMT_S24_PACKED; } else { d_print("unsupported sample format: %c%u_%s\n", sf_get_signed(oss_sf) ? 'S' : 'U', sf_get_bits(oss_sf), sf_get_bigendian(oss_sf) ? "BE" : "LE"); return -1; } if (ioctl(oss_fd, SNDCTL_DSP_SAMPLESIZE, &tmp) == -1) return -1; tmp = sf_get_rate(oss_sf); if (ioctl(oss_fd, SNDCTL_DSP_SPEED, &tmp) == -1) return -1; bytes_per_second = sf_get_second_size(oss_sf); log2_fragment_size = 0; while (1 << log2_fragment_size < bytes_per_second / 25) log2_fragment_size++; log2_fragment_size--; nr_fragments = 32; /* bits 0..15 = size of fragment, 16..31 = log2(number of fragments) */ tmp = (nr_fragments << 16) + log2_fragment_size; if (ioctl(oss_fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1) return -1; return 0; }