ATTN: Andrej Mitrovic: Port Audio
Johnson via Digitalmars-d-learn
digitalmars-d-learn at puremagic.com
Sat Aug 26 19:00:22 PDT 2017
You wrote a thread a while back about your callbacks not being
called and you had a fix.
http://www.digitalmars.com/d/archives/digitalmars/D/learn/Anyone_using_Portaudio_22343.html
I'm trying to get portAudio to work on my machine and it seems
everything passes yet my callbacks are not being called.
I do not know if it is the same issue you had or what. Could you
describe your fixes, if you remember? You said it was alias
issues, my source uses alias, so maybe I have the updated one.
Also, using paPrimeOutputBuffersUsingStreamCallback causes an
access violation ;/
Here are some dll's I'm using
https://github.com/spatialaudio/portaudio-binaries
I'm including the two files needed to compile what I have in case
you(or anyone else) decide to help figure this out:
Make sure to change the dll location in the DLL_PortAudio struct
and set the appropriate audio interface to use(I have it set to
12, but have tried every value on my system with no luck).
module mPortAudio;
import std.stdio, std.conv;
enum PaError : int
{
NoError = 0,
NotInitialized = -10000,
UnanticipatedHostError,
InvalidChannelCount,
InvalidSampleRate,
InvalidDevice,
InvalidFlag,
SampleFormatNotSupported,
BadIODeviceCombination,
InsufficientMemory,
BufferTooBig,
BufferTooSmall,
NullCallback,
BadStreamPtr,
TimedOut,
InternalError,
DeviceUnavailable,
IncompatibleHostApiSpecificStreamInfo,
StreamIsStopped,
StreamIsNotStopped,
InputOverflowed,
OutputUnderflowed,
HostApiNotFound,
InvalidHostApi,
CanNotReadFromACallbackStream,
CanNotWriteToACallbackStream,
CanNotReadFromAnOutputOnlyStream,
CanNotWriteToAnInputOnlyStream,
IncompatibleStreamHostApi,
BadBufferPtr,
FormatIsSupported = 0,
};
enum PaSampleFormat : ulong
{
Float32 = 0x00000001,
Int32 = 0x00000002,
Int24 = 0x00000004,
Int16 = 0x00000008,
Int8 = 0x00000010,
UInt8 = 0x00000020,
CustomFormat = 0x00010000,
NonInterleaved = 0x80000000
}
enum PaHostApiTypeId : int
{
InDevelopment=0,
DirectSound=1,
MME=2,
ASIO=3,
SoundManager=4,
CoreAudio=5,
OSS=7,
ALSA=8,
AL=9,
BeOS=10,
WDMKS=11,
JACK=12,
WASAPI=13,
AudioScienceHPI=14
};
enum PaStreamCallbackResult : int
{
paContinue=0, /**< Signal that the stream should continue
invoking the callback and processing audio. */
paComplete=1, /**< Signal that the stream should stop
invoking the callback and finish once all output samples have
played. */
paAbort=2 /**< Signal that the stream should stop
invoking the callback and finish as soon as possible. */
};
enum PaStreamFlags : ulong
{
NoFlag = 0,
ClipOff = 0x00000001,
DitherOff = 0x00000002,
NeverDropInput = 0x00000004,
PrimeOutputBuffersUsingStreamCallback = 0x00000008,
PlatformSpecificFlags = 0xFFFF0000,
}
alias void PaStream;
enum paFramesPerBufferUnspecified = 0;
enum PaStreamCallbackFlags : ulong
{
InputUnderflow = 0x00000001,
InputOverflow = 0x00000002,
OutputUnderflow = 0x00000004,
OutputOverflow = 0x00000008,
PrimingOutput = 0x00000010,
}
alias extern(C) int function(const(void) *input, void *output,
ulong frameCount, const(PaStreamCallbackTimeInfo)* timeInfo,
PaStreamCallbackFlags statusFlags, void *userData )
PaStreamCallback;
alias void function( void *userData ) PaStreamFinishedCallback;
alias int PaDeviceIndex;
enum paNoDevice = cast(PaDeviceIndex)-1;
enum paUseHostApiSpecificDeviceSpecification =
cast(PaDeviceIndex)-2;
alias int PaHostApiIndex;
alias double PaTime;
struct PaHostApiInfo
{
int structVersion;
PaHostApiTypeId type;
const(char) *name;
int deviceCount;
PaDeviceIndex defaultInputDevice;
PaDeviceIndex defaultOutputDevice;
};
struct PaDeviceInfo
{
int structVersion;
const(char) *name;
PaHostApiIndex hostApi;
int maxInputChannels;
int maxOutputChannels;
PaTime defaultLowInputLatency;
PaTime defaultLowOutputLatency;
PaTime defaultHighInputLatency;
PaTime defaultHighOutputLatency;
double defaultSampleRate;
};
struct PaStreamCallbackTimeInfo
{
PaTime inputBufferAdcTime;
PaTime currentTime;
PaTime outputBufferDacTime;
};
struct PaStreamInfo
{
int structVersion;
PaTime inputLatency;
PaTime outputLatency;
double sampleRate;
};
struct PaHostErrorInfo
{
PaHostApiTypeId hostApiType;
long errorCode;
const(char) *errorText;
};
struct PaStreamParameters
{
PaDeviceIndex device;
int channelCount;
PaSampleFormat sampleFormat;
PaTime suggestedLatency;
void *hostApiSpecificStreamInfo;
};
struct DLL_PortAudio
{
@("DLLImport") public static extern(Windows)
{
@(r"D:\D\DLLs\portaudio_x86.dll")
{
int function() Pa_GetVersion;
const(char)* function() Pa_GetVersionText;
const(char) *function(PaError errorCode) Pa_GetErrorText;
PaError function() Pa_Initialize;
PaError function() Pa_Terminate;
PaHostApiIndex function() Pa_GetHostApiCount;
PaHostApiIndex function() Pa_GetDefaultHostApi;
const(PaHostApiInfo)* function(PaHostApiIndex hostApi)
Pa_GetHostApiInfo;
PaHostApiIndex function(PaHostApiTypeId type)
Pa_HostApiTypeIdToHostApiIndex;
PaDeviceIndex function(PaHostApiIndex hostApi, int
hostApiDeviceIndex) Pa_HostApiDeviceIndexToDeviceIndex;
const(PaHostErrorInfo)* function() Pa_GetLastHostErrorInfo;
PaDeviceIndex function() Pa_GetDeviceCount;
PaDeviceIndex function() Pa_GetDefaultInputDevice;
PaDeviceIndex function() Pa_GetDefaultOutputDevice;
const(PaDeviceInfo)* function(PaDeviceIndex device)
Pa_GetDeviceInfo;
PaError function(PaStream *stream, PaStreamFinishedCallback
streamFinishedCallback) Pa_SetStreamFinishedCallback;
PaError function(PaStream *stream) Pa_StartStream;
PaError function(PaStream *stream) Pa_StopStream;
PaError function(PaStream *stream) Pa_AbortStream;
PaError function(PaStream *stream) Pa_IsStreamStopped;
PaError function(PaStream *stream) Pa_IsStreamActive;
PaError function(PaStream* stream, void *buffer, ulong frames)
Pa_ReadStream;
const(PaStreamInfo)* function(PaStream *stream)
Pa_GetStreamInfo;
PaTime function(PaStream *stream) Pa_GetStreamTime;
double function(PaStream* stream) Pa_GetStreamCpuLoad;
PaError function(PaStream* stream, const void *buffer, ulong
frames) Pa_WriteStream;
long function(PaStream* stream) Pa_GetStreamReadAvailable;
long function(PaStream* stream) Pa_GetStreamWriteAvailable;
PaError function(PaSampleFormat format) Pa_GetSampleSize;
void function(long msec) Pa_Sleep;
PaError function(PaStream** stream, const PaStreamParameters
*inputParameters, const PaStreamParameters *outputParameters,
double sampleRate, ulong framesPerBuffer, PaStreamFlags
streamFlags, PaStreamCallback streamCallback, void *userData)
Pa_OpenStream;
PaError function(PaStream** stream, int numInputChannels, int
numOutputChannels, PaSampleFormat sampleFormat, double
sampleRate, ulong framesPerBuffer, PaStreamCallback
streamCallback, void *userData) Pa_OpenDefaultStream;
PaError function(PaStream *stream) Pa_CloseStream;
PaError function(const PaStreamParameters *inputParameters,
const PaStreamParameters *outputParameters, double sampleRate)
Pa_IsFormatSupported;
}
}
}
// Fixes static functions and function pointers to point to their
specified DLL's
static this()
{
version(Windows)
{
import DLLImport;
ImportDLLs!DLL_PortAudio;
}
}
struct Phase
{
float left=0, right=0;
}
bool callbackCalled = false;
extern(C) int sawtooth(const(void)* inputBuffer, void*
outputBuffer, ulong framesPerBuffer,
const(PaStreamCallbackTimeInfo)* timeInfo, PaStreamCallbackFlags
statusFlags, void *userData)
{
callbackCalled = true;
auto phase = cast(Phase*)userData;
auto pout = cast(float*)outputBuffer;
enum vol = 1f;
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 1;
}
int main()
{
import core.stdc.stdio, std.stdio, std.conv;
with(DLL_PortAudio)
{
enum NUM_SECONDS = 5;
PaStream* stream;
PaError err;
Phase phase_data;
if ((err = Pa_Initialize()) == PaError.NoError)
{
writeln("---------------------------------------------------------------------------");
auto numDevices = Pa_GetDeviceCount();
if(numDevices < 0)
{
printf("ERROR: Pa_CountDevices returned 0x%x\n", numDevices);
err = cast(PaError)numDevices;
goto Lerror;
}
for(auto i = 0; i < numDevices; i++ )
{
auto deviceInfo = Pa_GetDeviceInfo(i);
auto deviceApiInfo = Pa_GetHostApiInfo(deviceInfo.hostApi);
write("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));
write(", "~to!string(deviceApiInfo.name)~",
"~to!string(deviceApiInfo.type));
writeln();
}
double sampleRate = 44100;
PaStreamParameters* input; // = new PaStreamParameters();
if (input != null)
{
input.device = 12;
auto id = Pa_GetDeviceInfo(input.device);
input.hostApiSpecificStreamInfo = null;
input.channelCount = id.maxInputChannels;
input.sampleFormat = PaSampleFormat.Float32;
input.suggestedLatency = (id.defaultLowInputLatency +
id.defaultHighInputLatency)/2;
sampleRate = id.defaultSampleRate;
}
PaStreamParameters* output = new PaStreamParameters();
if (output != null)
{
output.device = 12;
auto od = Pa_GetDeviceInfo(output.device);
output.hostApiSpecificStreamInfo = null;
output.channelCount = od.maxOutputChannels;
output.sampleFormat = PaSampleFormat.Float32;
output.suggestedLatency = (od.defaultLowOutputLatency +
od.defaultHighOutputLatency)/2;
sampleRate = od.defaultSampleRate;
} else
{
writeln("ERROR: Invalid output stream Parameters");
return -1;
}
Pa_SetStreamFinishedCallback(&stream, (data) {
writeln("WFWFWEFWEFWEF"); });
writeln("Opening Device!");
if ((err = Pa_OpenStream(&stream, input, output, sampleRate,
cast(ulong)paFramesPerBufferUnspecified,
cast(PaStreamFlags)(PaStreamFlags.NoFlag +
0*PaStreamFlags.PrimeOutputBuffersUsingStreamCallback),
&sawtooth, &phase_data)) != PaError.NoError) goto Lerror;
writeln("Starting Device!");
if ((err = Pa_StartStream(stream)) != PaError.NoError) goto
Lerror;
Pa_Sleep(NUM_SECONDS * 1000);
writeln("Stopping Device!");
if ((err = Pa_StopStream(stream)) != PaError.NoError) goto
Lerror;
if ((err = Pa_CloseStream(stream)) != PaError.NoError) goto
Lerror;
if ((err = Pa_Terminate()) != PaError.NoError) goto Lerror;
if (!callbackCalled) writeln("Callback was not called!");
writeln("DONE!");
getchar();
return 0;
} else
{
Lerror:
writeln(to!string(Pa_GetErrorText(err)));
getchar();
return 1;
}
}
return 0;
}
module DLLImport;
void ImportDLLs(T)()
{
version(Windows)
{
import core.sys.windows.windows, std.conv, std.meta, std.traits;
HINSTANCE[string] DLLs;
foreach(fname; __traits(allMembers, T))
{
mixin("enum isf = isFunction!(T."~fname~");");
mixin("enum isfp = isFunctionPointer!(T."~fname~");");
mixin("enum attrs = __traits(getAttributes, T."~fname~");");
static if ((isf || isfp) && attrs.length == 2 && attrs[0] ==
"DLLImport")
{
auto dllName = attrs[1];
if (dllName !in DLLs)
DLLs[dllName] = LoadLibrary(to!wstring(dllName~"\0").ptr);
auto dll = DLLs[dllName];
if (dll == null)
assert(0, "Cannot load DLL `"~dllName~"'");
auto func = GetProcAddress(dll, fname);
mixin("import "~moduleName!(T)~";");
static if (isf)
mixin("auto p = cast(void**)&"~T.stringof~"."~fname~"; *p =
cast(typeof(p))func;");
else static if (isfp)
mixin(""~T.stringof~"."~fname~" =
cast(typeof("~T.stringof~"."~fname~"))func;");
else
static assert("DLLImport Error");
}
}
}
}
More information about the Digitalmars-d-learn
mailing list