kopia lustrzana https://github.com/rs1729/RS
461 wiersze
13 KiB
C
461 wiersze
13 KiB
C
|
|
/*
|
|
* - load portaudio.dll
|
|
* - output device n to stdout
|
|
*
|
|
* win:
|
|
* gcc -DWIN_DLL pa-stdout.c
|
|
* (cl /DWIN_DLL /DCYGWIN pa-stdout.c)
|
|
* gcc -DWIN_DLL -DPA_DLL=\"PortAudio.dll\" pa-stdout.c
|
|
*
|
|
* linux:
|
|
* gcc pa-stdout.c -lportaudio
|
|
*
|
|
* [select SDR Audio Output channel]
|
|
* ./pa-stdout.exe --list
|
|
* ./pa-stdout.exe [devNo] | ./rs41mod.exe -vx --ptu
|
|
* ./pa-stdout.exe --line [lineNo] | ./rs41mod.exe -vx --ptu
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#ifdef WIN_DLL
|
|
#include <windows.h>
|
|
#endif
|
|
|
|
#ifdef CYGWIN
|
|
#include <fcntl.h> // cygwin: _setmode()
|
|
#include <io.h>
|
|
#endif
|
|
|
|
|
|
#ifndef WIN_DLL
|
|
#include "portaudio.h"
|
|
#else
|
|
//
|
|
//------------------------------------------------------------------------------------------------------
|
|
|
|
#define paNoDevice ((PaDeviceIndex)-1)
|
|
|
|
#define paClipOff ((PaStreamFlags) 0x00000001)
|
|
|
|
#define paFloat32 ((PaSampleFormat) 0x00000001) /**< @see PaSampleFormat */
|
|
#define paInt32 ((PaSampleFormat) 0x00000002) /**< @see PaSampleFormat */
|
|
#define paInt24 ((PaSampleFormat) 0x00000004) /**< Packed 24 bit format. @see PaSampleFormat */
|
|
#define paInt16 ((PaSampleFormat) 0x00000008) /**< @see PaSampleFormat */
|
|
#define paInt8 ((PaSampleFormat) 0x00000010) /**< @see PaSampleFormat */
|
|
#define paUInt8 ((PaSampleFormat) 0x00000020) /**< @see PaSampleFormat */
|
|
#define paCustomFormat ((PaSampleFormat) 0x00010000) /**< @see PaSampleFormat */
|
|
|
|
|
|
typedef int PaError;
|
|
typedef enum PaErrorCode
|
|
{
|
|
paNoError = 0,
|
|
paNotInitialized = -10000,
|
|
paUnanticipatedHostError,
|
|
paInvalidChannelCount,
|
|
paInvalidSampleRate,
|
|
paInvalidDevice,
|
|
paInvalidFlag,
|
|
paSampleFormatNotSupported,
|
|
paBadIODeviceCombination,
|
|
paInsufficientMemory,
|
|
paBufferTooBig,
|
|
paBufferTooSmall,
|
|
paNullCallback,
|
|
paBadStreamPtr,
|
|
paTimedOut,
|
|
paInternalError,
|
|
paDeviceUnavailable,
|
|
paIncompatibleHostApiSpecificStreamInfo,
|
|
paStreamIsStopped,
|
|
paStreamIsNotStopped,
|
|
paInputOverflowed,
|
|
paOutputUnderflowed,
|
|
paHostApiNotFound,
|
|
paInvalidHostApi,
|
|
paCanNotReadFromACallbackStream,
|
|
paCanNotWriteToACallbackStream,
|
|
paCanNotReadFromAnOutputOnlyStream,
|
|
paCanNotWriteToAnInputOnlyStream,
|
|
paIncompatibleStreamHostApi,
|
|
paBadBufferPtr
|
|
} PaErrorCode;
|
|
|
|
typedef int PaDeviceIndex;
|
|
typedef int PaHostApiIndex;
|
|
typedef double PaTime;
|
|
|
|
typedef struct PaDeviceInfo
|
|
{
|
|
int structVersion; /* this is struct version 2 */
|
|
const char *name;
|
|
PaHostApiIndex hostApi; /**< note this is a host API index, not a type id*/
|
|
|
|
int maxInputChannels;
|
|
int maxOutputChannels;
|
|
|
|
/** Default latency values for interactive performance. */
|
|
PaTime defaultLowInputLatency;
|
|
PaTime defaultLowOutputLatency;
|
|
/** Default latency values for robust non-interactive applications (eg. playing sound files). */
|
|
PaTime defaultHighInputLatency;
|
|
PaTime defaultHighOutputLatency;
|
|
|
|
double defaultSampleRate;
|
|
} PaDeviceInfo;
|
|
|
|
|
|
typedef unsigned long PaStreamFlags;
|
|
typedef unsigned long PaSampleFormat;
|
|
|
|
typedef struct PaStreamCallbackTimeInfo{
|
|
PaTime inputBufferAdcTime; /**< The time when the first sample of the input buffer was captured at the ADC input */
|
|
PaTime currentTime; /**< The time when the stream callback was invoked */
|
|
PaTime outputBufferDacTime; /**< The time when the first sample of the output buffer will output the DAC */
|
|
} PaStreamCallbackTimeInfo;
|
|
|
|
typedef unsigned long PaStreamCallbackFlags;
|
|
|
|
|
|
typedef struct PaStreamParameters
|
|
{
|
|
PaDeviceIndex device;
|
|
int channelCount;
|
|
PaSampleFormat sampleFormat;
|
|
PaTime suggestedLatency;
|
|
void *hostApiSpecificStreamInfo;
|
|
|
|
} PaStreamParameters;
|
|
|
|
typedef void PaStream;
|
|
|
|
typedef int PaStreamCallback(
|
|
const void *input, void *output,
|
|
unsigned long frameCount,
|
|
const PaStreamCallbackTimeInfo* timeInfo,
|
|
PaStreamCallbackFlags statusFlags,
|
|
void *userData );
|
|
|
|
//
|
|
//------------------------------------------------------------------------------------------------------
|
|
|
|
// load WIN-DLL
|
|
|
|
// prototypes ( __cdecl -> WINAPIV , __stdcall -> WINAPI )
|
|
#define CALLCONV WINAPIV // __cdecl
|
|
|
|
typedef int (CALLCONV* t_Pa_Initialize)(void);
|
|
typedef int (CALLCONV* t_Pa_GetDefaultInputDevice)(void);
|
|
typedef int (CALLCONV* t_Pa_GetDeviceCount)(void);
|
|
|
|
typedef PaDeviceInfo* (CALLCONV* t_Pa_GetDeviceInfo)(PaDeviceIndex device);
|
|
|
|
t_Pa_Initialize Pa_Initialize;
|
|
t_Pa_GetDefaultInputDevice Pa_GetDefaultInputDevice;
|
|
t_Pa_GetDeviceCount Pa_GetDeviceCount;
|
|
t_Pa_GetDeviceInfo Pa_GetDeviceInfo;
|
|
|
|
|
|
typedef int (CALLCONV* t_Pa_OpenStream)(PaStream**,PaStreamParameters*,PaStreamParameters*,double,
|
|
unsigned long,PaStreamFlags,PaStreamCallback*,void*);
|
|
typedef int (CALLCONV* t_Pa_StartStream)(PaStream*);
|
|
typedef int (CALLCONV* t_Pa_ReadStream)(PaStream*,void*,unsigned long);
|
|
typedef int (CALLCONV* t_Pa_CloseStream)(PaStream*);
|
|
typedef int (CALLCONV* t_Pa_Terminate)(void);
|
|
typedef char* (CALLCONV* t_Pa_GetErrorText)(PaError);
|
|
|
|
t_Pa_OpenStream Pa_OpenStream;
|
|
t_Pa_StartStream Pa_StartStream;
|
|
t_Pa_ReadStream Pa_ReadStream;
|
|
t_Pa_CloseStream Pa_CloseStream;
|
|
t_Pa_Terminate Pa_Terminate;
|
|
t_Pa_GetErrorText Pa_GetErrorText;
|
|
|
|
|
|
HINSTANCE pa_handle;
|
|
|
|
|
|
int adr_functions() {
|
|
|
|
int ret = 0;
|
|
|
|
Pa_Initialize = (t_Pa_Initialize)GetProcAddress(pa_handle, "Pa_Initialize");
|
|
if (Pa_Initialize == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_GetDefaultInputDevice = (t_Pa_GetDefaultInputDevice)GetProcAddress(pa_handle, "Pa_GetDefaultInputDevice");
|
|
if (Pa_GetDefaultInputDevice == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_GetDeviceCount = (t_Pa_GetDeviceCount)GetProcAddress(pa_handle, "Pa_GetDeviceCount");
|
|
if (Pa_GetDeviceCount == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_GetDeviceInfo = (t_Pa_GetDeviceInfo)GetProcAddress(pa_handle, "Pa_GetDeviceInfo");
|
|
if (Pa_GetDeviceInfo == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_OpenStream = (t_Pa_OpenStream)GetProcAddress(pa_handle, "Pa_OpenStream");
|
|
if (Pa_OpenStream == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_StartStream = (t_Pa_StartStream)GetProcAddress(pa_handle, "Pa_StartStream");
|
|
if (Pa_StartStream == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_ReadStream = (t_Pa_ReadStream)GetProcAddress(pa_handle, "Pa_ReadStream");
|
|
if (Pa_ReadStream == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_CloseStream = (t_Pa_CloseStream)GetProcAddress(pa_handle, "Pa_CloseStream");
|
|
if (Pa_CloseStream == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_Terminate = (t_Pa_Terminate)GetProcAddress(pa_handle, "Pa_Terminate");
|
|
if (Pa_Terminate == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
Pa_GetErrorText = (t_Pa_GetErrorText)GetProcAddress(pa_handle, "Pa_GetErrorText");
|
|
if (Pa_GetErrorText == NULL) {
|
|
fprintf(stderr, "ERROR: GetProcAddress\n");
|
|
ret = -2;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
|
|
#define SAMPLE_RATE (48000)
|
|
#define FRAMES_PER_BUFFER (1024)
|
|
#define N_CH (0x02)
|
|
|
|
// 16-bit int samples
|
|
#define PA_SAMPLE_TYPE paInt16
|
|
typedef short SAMPLE; // 16-bit
|
|
|
|
|
|
int get_Devices(int list) {
|
|
int i;
|
|
PaDeviceIndex numDevices = Pa_GetDeviceCount();
|
|
|
|
fprintf(stderr, "#devices: %d\n", numDevices);
|
|
|
|
if (list)
|
|
{
|
|
for (i = 0; i < numDevices; i++)
|
|
{
|
|
const PaDeviceInfo *devInfo = Pa_GetDeviceInfo(i);
|
|
fprintf(stderr, "[%2d] %s\n", i, devInfo->name);
|
|
}
|
|
}
|
|
|
|
return numDevices;
|
|
}
|
|
|
|
int get_Line(int lineNo, int *devNo) {
|
|
int i;
|
|
const PaDeviceIndex numDevices = Pa_GetDeviceCount();
|
|
const PaDeviceInfo *devInfo = NULL;
|
|
char strbuf[32];
|
|
|
|
sprintf(strbuf, "Line %d", lineNo % 100);
|
|
|
|
fprintf(stderr, "#devices: %d\n", numDevices);
|
|
|
|
for (i = 0; i < numDevices; i++)
|
|
{
|
|
devInfo = Pa_GetDeviceInfo(i);
|
|
if ( strstr(devInfo->name, strbuf) ) {
|
|
*devNo = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return numDevices;
|
|
}
|
|
|
|
|
|
unsigned char wav_hdr[] = { // 0x80, 0xbb, 0x00, 0x00: sample_rate=48000
|
|
0x52, 0x49, 0x46, 0x46, 0x24, 0xf0, 0xff, 0x7f, 0x57, 0x41, 0x56, 0x45, 0x66, 0x6d, 0x74, 0x20,
|
|
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, N_CH, 0x00, 0x80, 0xbb, 0x00, 0x00, 0x00, 0xee, 0x02, 0x00,
|
|
0x04, 0x00, 0x10, 0x00, 0x64, 0x61, 0x74, 0x61, 0x00, 0xf0, 0xff, 0x7f};
|
|
//0x10,0x00: bits/sample=16 // 0x0n, 0x00: channels=n
|
|
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
int ret = 0;
|
|
|
|
int devNo = -1,
|
|
numDevices = 0,
|
|
list = 0,
|
|
lineNo = -1;
|
|
|
|
PaError err = paNoError;
|
|
PaStreamParameters inputParameters;
|
|
PaStream *stream;
|
|
const PaDeviceInfo *devInfo = NULL;
|
|
|
|
SAMPLE *dataSamples = NULL;
|
|
int totalFrames;
|
|
int numSamples;
|
|
|
|
|
|
#ifdef CYGWIN
|
|
_setmode(fileno(stdout), _O_BINARY); // _setmode(_fileno(stdout), _O_BINARY);
|
|
#endif
|
|
//setvbuf(stdout, NULL, _IOFBF, 128); // buffered
|
|
//setvbuf(stdout, NULL, _IONBF, 0); // unbuffered
|
|
setbuf(stdout, NULL); // unbuffered
|
|
setbuf(stderr, NULL);
|
|
|
|
|
|
#ifdef WIN_DLL
|
|
{
|
|
char *dll_path = "PortAudio.dll"; // x86/x64 (same as gcc/cl)
|
|
// gcc -DPA_DLL=\"PortAudio_x64.dll\" ...
|
|
#ifdef PA_DLL
|
|
dll_path = PA_DLL;
|
|
#endif
|
|
|
|
pa_handle = LoadLibrary(dll_path);
|
|
|
|
if (pa_handle == NULL) {
|
|
fprintf(stderr, "ERROR: loadlibrary\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = adr_functions();
|
|
if (ret != 0) goto error;
|
|
}
|
|
#endif
|
|
|
|
|
|
err = Pa_Initialize();
|
|
if ( err != paNoError ) goto done;
|
|
|
|
|
|
if (argv[1]) {
|
|
devNo = -1;
|
|
lineNo = -1;
|
|
if (strcmp(argv[1], "--list") == 0) {
|
|
list = 1;
|
|
devNo = -1;
|
|
}
|
|
else if (strcmp(argv[1], "--line") == 0) {
|
|
if (argv[2]) lineNo = atoi(argv[2]);
|
|
}
|
|
else {
|
|
devNo = atoi(argv[1]);
|
|
}
|
|
if (devNo == 0 && argv[1][0] != '0') devNo = -1;
|
|
}
|
|
|
|
if (lineNo >= 0) numDevices = get_Line(lineNo, &devNo);
|
|
else numDevices = get_Devices(list);
|
|
if ( list ) goto done;
|
|
|
|
if ( devNo >= numDevices ) devNo = -1;
|
|
|
|
|
|
totalFrames = FRAMES_PER_BUFFER;
|
|
numSamples = totalFrames * N_CH;
|
|
dataSamples = (SAMPLE *) calloc( numSamples, sizeof(SAMPLE) );
|
|
if ( dataSamples == NULL )
|
|
{
|
|
fprintf(stderr, "ERROR: malloc\n");
|
|
goto done;
|
|
}
|
|
|
|
|
|
if (devNo < 0) inputParameters.device = Pa_GetDefaultInputDevice();
|
|
else inputParameters.device = devNo;
|
|
|
|
fprintf(stderr, "Input Device:\n");
|
|
devInfo = Pa_GetDeviceInfo(inputParameters.device);
|
|
fprintf(stderr, "[%d] %s\n", inputParameters.device, devInfo->name);
|
|
|
|
if (inputParameters.device == paNoDevice) {
|
|
fprintf(stderr,"Error: No default input device.\n");
|
|
goto done;
|
|
}
|
|
|
|
inputParameters.channelCount = N_CH;
|
|
inputParameters.sampleFormat = PA_SAMPLE_TYPE;
|
|
inputParameters.suggestedLatency = Pa_GetDeviceInfo( inputParameters.device )->defaultLowInputLatency;
|
|
inputParameters.hostApiSpecificStreamInfo = NULL;
|
|
|
|
|
|
err = Pa_OpenStream(
|
|
&stream,
|
|
&inputParameters,
|
|
NULL, // &outputParameters,
|
|
SAMPLE_RATE,
|
|
FRAMES_PER_BUFFER,
|
|
paClipOff,
|
|
NULL,
|
|
NULL );
|
|
if ( err != paNoError ) goto done;
|
|
|
|
err = Pa_StartStream( stream );
|
|
if ( err != paNoError ) goto done;
|
|
|
|
fwrite( wav_hdr, 1, sizeof(wav_hdr)/*44*/, stdout );
|
|
while (1) {
|
|
err = Pa_ReadStream( stream, dataSamples, totalFrames );
|
|
if ( err != paNoError ) {
|
|
if ( err != paInputOverflowed) goto done;
|
|
//fprintf(stderr, "Error: %d (%s)\n", err, Pa_GetErrorText( err ) );
|
|
// // dataSamples...
|
|
}
|
|
|
|
fwrite( dataSamples, N_CH * sizeof(SAMPLE), totalFrames, stdout );
|
|
}
|
|
|
|
err = Pa_CloseStream( stream );
|
|
if ( err != paNoError ) goto done;
|
|
|
|
|
|
done:
|
|
Pa_Terminate();
|
|
if ( dataSamples ) free(dataSamples);
|
|
if ( err != paNoError )
|
|
{
|
|
fprintf( stderr, "Error number: %d\n", err );
|
|
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
|
|
err = 1; /* Always return 0 or 1, but no other return codes. */
|
|
}
|
|
|
|
error:
|
|
#ifdef WIN_DLL
|
|
FreeLibrary(pa_handle);
|
|
#endif
|
|
if (ret) err = ret;
|
|
|
|
return err;
|
|
}
|
|
|