Heres a better version that automatically generates a class
wrapping the portaudio.dll. Need portaudio.di(possibly renamed to
portaudio.d and imported). Still same problem as original though.
import portaudio;
import std.conv, std.stdio;
import core.stdc.stdio;
alias BOOL = ubyte;
alias DWORD = uint;
auto BuildDLLClassFromCHeader(alias modulename, string name)()
{
import std.traits, std.algorithm, std.meta;
auto s = "extern (C) class " ~name~"\n{\n\timport ___import =
"~moduleName!modulename~";\n";
mixin("import "~moduleName!modulename~";");
foreach(m; AliasSeq!(__traits(allMembers, modulename)))
{
mixin("alias member = " ~ fullyQualifiedName!(modulename) ~ "."
~ m ~ ";");
static if (is(typeof(member) == function))
static if (functionLinkage!member != "C")
continue;
else
s ~= "\tpublic static typeof(___import."~__traits(identifier,
member)~")* "~__traits(identifier, member)~";\n";
}
return s ~ "}";
}
void DllImport(alias T)(string dllName)
{
import core.sys.windows.windows, std.conv, std.meta;
auto dll = LoadLibrary(to!wstring(dllName~"\0").ptr);
if (dll == null)
assert(0, "Cannot load DLL `"~dllName~"'");
foreach(fname; __traits(derivedMembers, T))
{
auto func = GetProcAddress(dll, fname);
enum s = "auto p = cast(void**)&"~T.stringof~"."~fname~"; *p =
cast(typeof(p))func;";
mixin(s);
}
}
mixin(BuildDLLClassFromCHeader!(portaudio, "PortAudioDLL")());
struct Phase
{
float left=0, right=0;
}
bool test = false;
extern(C) int sawtooth(const(void)* inputBuffer, void*
outputBuffer, size_t framesPerBuffer,
const(PaStreamCallbackTimeInfo)* timeInfo, PaStreamCallbackFlags
statusFlags, void *userData)
{
test = true;
auto phase = cast(Phase*)userData;
auto pout = cast(float*)outputBuffer;
enum vol = 0.2f;
foreach(i; 0 .. framesPerBuffer)
{
*pout++ = vol * phase.left;
*pout++ = vol * phase.right;
phase.left += 0.01f;
if (phase.left >= 1.0f) phase.left -= 2.0f;
phase.right += 0.03f;
if (phase.right >= 1.0f) phase.right -= 2.0f;
}
return 0;
}
int main()
{
DllImport!PortAudioDLL("portaudio_x86.dll");
with(PortAudioDLL)
{
enum NUM_SECONDS = 5;
PaStream* stream;
PaError err;
Phase phase_data;
if ((err = Pa_Initialize()) == paNoError)
{
writeln("---------------------------------------------------------------------------");
auto numDevices = Pa_GetDeviceCount();
if(numDevices < 0)
{
printf("ERROR: Pa_CountDevices returned
0x%x\n", numDevices);
err = numDevices;
goto Lerror;
}
for(auto i = 0; i < numDevices; i++ )
{
auto deviceInfo = Pa_GetDeviceInfo(i);
writeln("Device "~to!string(i)~" >
"~to!string(deviceInfo.name)~",
"~to!string(deviceInfo.maxInputChannels)~",
"~to!string(deviceInfo.maxOutputChannels)~",
"~to!string(deviceInfo.defaultLowOutputLatency)~","~to!string(deviceInfo.defaultHighOutputLatency)~", "~to!string(deviceInfo.defaultSampleRate)~", "~to!string(deviceInfo.hostApi));
}
double sampleRate = 44100;
PaStreamParameters* input;
if (input != null)
{
input.device = 0;
auto id = Pa_GetDeviceInfo(input.device);
input.hostApiSpecificStreamInfo = null;
input.channelCount = id.maxInputChannels;
input.sampleFormat = paFloat32;
input.suggestedLatency = (id.defaultLowInputLatency +
id.defaultHighInputLatency)/2;
sampleRate = id.defaultSampleRate;
}
PaStreamParameters* output = new PaStreamParameters();
if (output != null)
{
output.device = 9;
auto od = Pa_GetDeviceInfo(output.device);
output.hostApiSpecificStreamInfo = null;
output.channelCount = od.maxOutputChannels;
output.sampleFormat = paFloat32;
output.suggestedLatency = (od.defaultLowOutputLatency +
od.defaultHighOutputLatency)/2;
sampleRate = od.defaultSampleRate;
}
if ((err = Pa_OpenStream(&stream, input, output,
sampleRate, paFramesPerBufferUnspecified, paNoFlag,
&sawtooth, &phase_data)) != paNoError) goto Lerror;
if ((err = Pa_StartStream(stream)) != paNoError) goto
Lerror;
Pa_Sleep(NUM_SECONDS * 1000);
writeln(test);
if ((err = Pa_StopStream(stream)) != paNoError) goto
Lerror;
if ((err = Pa_CloseStream(stream)) != paNoError) goto
Lerror;
if ((err = Pa_Terminate()) != paNoError) goto Lerror;
writeln("DONE");
getchar();
return 0;
} else
{
Lerror:
writeln(to!string(Pa_GetErrorText(err)));
getchar();
return 1;
}
}
return 0;
}