diff --git a/tools/README.md b/tools/README.md index 2fdec4a..0f925c2 100644 --- a/tools/README.md +++ b/tools/README.md @@ -1,11 +1,11 @@ ## Tools -### convert decoder output + ### convert decoder output -* `pos2kml.pl`, `pos2gpx.pl`, `pos2nmea.pl`, `pos2aprs.pl`
+ * `pos2kml.pl`, `pos2gpx.pl`, `pos2nmea.pl`, `pos2aprs.pl`
perl scripts for kml-, gpx-, nmea- or aprs-output, resp. - #### Usage/Example + * Usage/Example
`./rs92ecc --ecc --crc -v --vel2 -e brdc3050.15n 2015101_14Z.wav | ./pos2nmea.pl`
`stderr`: frame output
`stdout`: NMEA output
@@ -13,3 +13,13 @@ `./rs92ecc --ecc --crc -v --vel2 -e brdc3050.15n 2015101_14Z.wav | ./pos2nmea.pl 2>/dev/null` + ### audio output to stdout + + * `pa-stdout.c`
+ select SDR Output device/stereo channel and output to stdout
+ * Usage/Example
+ `./pa-stdout --list`
+ `./pa-stdout 2 | ./rs41dm_dft --ecc2 --crc -vx --ptu`
+ ( audio device no 2 -> stdout -> ./rs41dm_dft ) + + diff --git a/tools/pa-stdout.c b/tools/pa-stdout.c new file mode 100644 index 0000000..3212893 --- /dev/null +++ b/tools/pa-stdout.c @@ -0,0 +1,404 @@ + +/* + * - load portaudio.dll + * - output device n to stdout + * + * win: + * gcc -DWIN_DLL pa-stdout.c + * (cl /DWIN_DLL /DCYGWIN pa-stdout.c) + * + * linux: + * gcc pa-stdout.c -lportaudio + * + * [select SDR Audio Output channel] + * ./pa-stdout.exe --list + * ./pa-stdout.exe [devNo] | ./rs41dm_dft.exe --ecc2 --crc -vx --ptu + */ + +#include +#include + +#ifdef WIN_DLL + #include +#endif + +#ifdef CYGWIN + #include // cygwin: _setmode() + #include +#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*) + +typedef int (WINAPI* t_Pa_Initialize)(void); +typedef int (WINAPI* t_Pa_GetDefaultInputDevice)(void); +typedef int (WINAPI* t_Pa_GetDeviceCount)(void); + +typedef PaDeviceInfo* (WINAPI* 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 (WINAPI* t_Pa_OpenStream)(PaStream**,PaStreamParameters*,PaStreamParameters*,double, + unsigned long,PaStreamFlags,PaStreamCallback*,void*); +typedef int (WINAPI* t_Pa_StartStream)(PaStream *); +typedef int (WINAPI* t_Pa_ReadStream)(PaStream*,void *,unsigned long); +typedef int (WINAPI* t_Pa_CloseStream)(PaStream*); +typedef int (WINAPI* t_Pa_Terminate)(void); +typedef char* (WINAPI* 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); + + for (i = 0; i < numDevices; i++) + { + PaDeviceInfo *devInfo = Pa_GetDeviceInfo(i); + if (list) fprintf(stderr, "[%2d] %s\n", i, devInfo->name); + } + + 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; + + PaError err = paNoError; + PaStreamParameters inputParameters; + PaStream *stream; + PaDeviceInfo *devInfo = NULL; + + SAMPLE *dataSamples = NULL; + int totalFrames; + int numSamples; + + +#ifdef CYGWIN + _setmode(fileno(stdout), _O_BINARY); // _setmode(_fileno(stdout), _O_BINARY); +#endif + setbuf(stdout, NULL); + setbuf(stderr, NULL); + + +#ifdef WIN_DLL + pa_handle = LoadLibrary("PortAudio.dll"); // x86/x64 (same as gcc/cl) + + 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]) { + if (strcmp(argv[1], "--list") == 0) list = 1; + devNo = atoi(argv[1]); + if (devNo == 0 && argv[1][0] != '0') devNo = -1; + } + + 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 ) goto done; + 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; +} +