configurable params

This commit is contained in:
Adam D. Ruppe 2020-05-11 21:52:30 -04:00
parent a450ca7e4c
commit 1534a7fa19
1 changed files with 44 additions and 22 deletions

View File

@ -198,9 +198,9 @@ struct AudioOutputThread {
just live as a dummy mock object that you should not actually just live as a dummy mock object that you should not actually
try to use. try to use.
+/ +/
this(bool enable) { this(bool enable, int SampleRate = 44100, int channels = 2) {
if(enable) { if(enable) {
impl = new AudioPcmOutThreadImplementation(); impl = new AudioPcmOutThreadImplementation(SampleRate, channels);
impl.refcount++; impl.refcount++;
impl.start(); impl.start();
impl.waitForInitialization(); impl.waitForInitialization();
@ -297,12 +297,17 @@ import core.thread;
--- ---
+/ +/
final class AudioPcmOutThreadImplementation : Thread { final class AudioPcmOutThreadImplementation : Thread {
private this() { private this(int SampleRate, int channels) {
this.isDaemon = true; this.isDaemon = true;
this.SampleRate = SampleRate;
this.channels = channels;
super(&run); super(&run);
} }
private int SampleRate;
private int channels;
private int refcount; private int refcount;
private void waitForInitialization() { private void waitForInitialization() {
@ -630,8 +635,6 @@ import core.stdc.config;
version(linux) version=ALSA; version(linux) version=ALSA;
version(Windows) version=WinMM; version(Windows) version=WinMM;
enum SampleRate = 44100;
version(ALSA) { version(ALSA) {
enum cardName = "default"; enum cardName = "default";
@ -690,12 +693,20 @@ struct AudioInput {
@disable this(); @disable this();
@disable this(this); @disable this(this);
int channels;
int SampleRate;
/// Always pass card == 0. /// Always pass card == 0.
this(int card) { this(int card, int SampleRate = 44100, int channels = 2) {
assert(card == 0); assert(card == 0);
assert(channels == 1 || channels == 2);
this.channels = channels;
this.SampleRate = SampleRate;
version(ALSA) { version(ALSA) {
handle = openAlsaPcm(snd_pcm_stream_t.SND_PCM_STREAM_CAPTURE); handle = openAlsaPcm(snd_pcm_stream_t.SND_PCM_STREAM_CAPTURE, SampleRate, channels);
} else version(WinMM) { } else version(WinMM) {
event = CreateEvent(null, false /* manual reset */, false /* initially triggered */, null); event = CreateEvent(null, false /* manual reset */, false /* initially triggered */, null);
@ -703,7 +714,7 @@ struct AudioInput {
format.wFormatTag = WAVE_FORMAT_PCM; format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = 2; format.nChannels = 2;
format.nSamplesPerSec = SampleRate; format.nSamplesPerSec = SampleRate;
format.nAvgBytesPerSec = SampleRate * 2 * 2; // two channels, two bytes per sample format.nAvgBytesPerSec = SampleRate * channels * 2; // two channels, two bytes per sample
format.nBlockAlign = 4; format.nBlockAlign = 4;
format.wBitsPerSample = 16; format.wBitsPerSample = 16;
format.cbSize = 0; format.cbSize = 0;
@ -724,11 +735,11 @@ struct AudioInput {
short[] read(short[] buffer) { short[] read(short[] buffer) {
snd_pcm_sframes_t read; snd_pcm_sframes_t read;
read = snd_pcm_readi(handle, buffer.ptr, buffer.length / 2 /* div number of channels apparently */); read = snd_pcm_readi(handle, buffer.ptr, buffer.length / channels /* div number of channels apparently */);
if(read < 0) if(read < 0)
throw new AlsaException("pcm read", cast(int)read); throw new AlsaException("pcm read", cast(int)read);
return buffer[0 .. read * 2]; return buffer[0 .. read * channels];
} }
/// passes a buffer of data to fill /// passes a buffer of data to fill
@ -840,6 +851,9 @@ struct AudioInput {
} }
} }
///
enum SampleRateFull = 44100;
/// Gives PCM output access (such as the speakers). /// Gives PCM output access (such as the speakers).
struct AudioOutput { struct AudioOutput {
version(ALSA) { version(ALSA) {
@ -853,18 +867,26 @@ struct AudioOutput {
// be passed to a device driver and stored! // be passed to a device driver and stored!
@disable this(this); @disable this(this);
private int SampleRate;
private int channels;
/// Always pass card == 0. /// Always pass card == 0.
this(int card) { this(int card, int SampleRate = 44100, int channels = 2) {
assert(card == 0); assert(card == 0);
assert(channels == 1 || channels == 2);
this.SampleRate = SampleRate;
this.channels = channels;
version(ALSA) { version(ALSA) {
handle = openAlsaPcm(snd_pcm_stream_t.SND_PCM_STREAM_PLAYBACK); handle = openAlsaPcm(snd_pcm_stream_t.SND_PCM_STREAM_PLAYBACK, SampleRate, channels);
} else version(WinMM) { } else version(WinMM) {
WAVEFORMATEX format; WAVEFORMATEX format;
format.wFormatTag = WAVE_FORMAT_PCM; format.wFormatTag = WAVE_FORMAT_PCM;
format.nChannels = 2; format.nChannels = cast(ushort) channels;
format.nSamplesPerSec = SampleRate; format.nSamplesPerSec = SampleRate;
format.nAvgBytesPerSec = SampleRate * 2 * 2; // two channels, two bytes per sample format.nAvgBytesPerSec = SampleRate * channels * 2; // two channels, two bytes per sample
format.nBlockAlign = 4; format.nBlockAlign = 4;
format.wBitsPerSample = 16; format.wBitsPerSample = 16;
format.cbSize = 0; format.cbSize = 0;
@ -875,8 +897,8 @@ struct AudioOutput {
/// passes a buffer of data to fill /// passes a buffer of data to fill
/// ///
/// Data is assumed to be interleaved stereo, LE 16 bit, 44.1 kHz /// Data is assumed to be interleaved stereo, LE 16 bit, 44.1 kHz (unless you change that in the ctor)
/// Each item in the array thus alternates between left and right channel /// Each item in the array thus alternates between left and right channel (unless you change that in the ctor)
/// and it takes a total of 88,200 items to make one second of sound. /// and it takes a total of 88,200 items to make one second of sound.
void delegate(short[]) fillData; void delegate(short[]) fillData;
@ -902,18 +924,18 @@ struct AudioOutput {
if(ready > BUFFER_SIZE_FRAMES) if(ready > BUFFER_SIZE_FRAMES)
ready = BUFFER_SIZE_FRAMES; ready = BUFFER_SIZE_FRAMES;
//import std.stdio; writeln("filling ", ready); //import std.stdio; writeln("filling ", ready);
fillData(buffer[0 .. ready * 2]); fillData(buffer[0 .. ready * channels]);
if(playing) { if(playing) {
snd_pcm_sframes_t written; snd_pcm_sframes_t written;
auto data = buffer[0 .. ready * 2]; auto data = buffer[0 .. ready * channels];
while(data.length) { while(data.length) {
written = snd_pcm_writei(handle, data.ptr, data.length / 2); written = snd_pcm_writei(handle, data.ptr, data.length / channels);
if(written < 0) { if(written < 0) {
written = snd_pcm_recover(handle, cast(int)written, 0); written = snd_pcm_recover(handle, cast(int)written, 0);
if (written < 0) throw new AlsaException("pcm write", cast(int)written); if (written < 0) throw new AlsaException("pcm write", cast(int)written);
} }
data = data[written * 2 .. $]; data = data[written * channels .. $];
} }
} }
} }
@ -1562,7 +1584,7 @@ Pitch Bend Change. 0mmmmmmm This message is sent to indicate a change in the pit
version(ALSA) version(ALSA)
// Opens the PCM device with default settings: stereo, 16 bit, 44.1 kHz, interleaved R/W. // Opens the PCM device with default settings: stereo, 16 bit, 44.1 kHz, interleaved R/W.
snd_pcm_t* openAlsaPcm(snd_pcm_stream_t direction) { snd_pcm_t* openAlsaPcm(snd_pcm_stream_t direction, int SampleRate, int channels) {
snd_pcm_t* handle; snd_pcm_t* handle;
snd_pcm_hw_params_t* hwParams; snd_pcm_hw_params_t* hwParams;
@ -1596,7 +1618,7 @@ snd_pcm_t* openAlsaPcm(snd_pcm_stream_t direction) {
assert(rate == SampleRate); // cheap me assert(rate == SampleRate); // cheap me
if (auto err = snd_pcm_hw_params_set_channels(handle, hwParams, 2)) if (auto err = snd_pcm_hw_params_set_channels(handle, hwParams, channels))
throw new AlsaException("params channels", err); throw new AlsaException("params channels", err);
uint periods = 2; uint periods = 2;