Update dsd.h, dsd_audio.c, dsd_main.c and dsd_symbol.c

Adding portaudio support. Implementing it as a new audio_..._type in dsd.h.

Update CMakeLists.txt and create FindLibPortAudio.cmake

CMake portaudio check
This commit is contained in:
jpwichern 2014-06-05 19:00:39 +02:00 committed by Jiri Wichern
parent df3c0dcab4
commit 55b190ef49
6 changed files with 381 additions and 14 deletions

View File

@ -9,6 +9,7 @@ git_describe(GIT_TAG)
find_package(LibSndFile REQUIRED) find_package(LibSndFile REQUIRED)
find_package(LibMbe REQUIRED) find_package(LibMbe REQUIRED)
find_package(ITPP REQUIRED) find_package(ITPP REQUIRED)
find_package(LibPortAudio)
FILE(GLOB SRCS *.c *.cpp) FILE(GLOB SRCS *.c *.cpp)
@ -24,6 +25,12 @@ INCLUDE_DIRECTORIES(
SET(LIBS ${LIBS} ${LIBMBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY}) SET(LIBS ${LIBS} ${LIBMBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY})
if(PORTAUDIO_FOUND)
SET(INCLUDE_DIRECTORIES ${INCLUDE_DIRECTORIES} "${PORTAUDIO_INCLUDE_DIRS}")
SET(LIBS ${LIBS} ${PORTAUDIO_LIBRARIES})
add_definitions(-DUSE_PORTAUDIO)
endif(PORTAUDIO_FOUND)
ADD_EXECUTABLE(dsd ${SRCS}) ADD_EXECUTABLE(dsd ${SRCS})
TARGET_LINK_LIBRARIES(dsd ${LIBS}) TARGET_LINK_LIBRARIES(dsd ${LIBS})

View File

@ -0,0 +1,108 @@
# - Try to find Portaudio
# Once done this will define
#
# PORTAUDIO_FOUND - system has Portaudio
# PORTAUDIO_INCLUDE_DIRS - the Portaudio include directory
# PORTAUDIO_LIBRARIES - Link these to use Portaudio
# PORTAUDIO_DEFINITIONS - Compiler switches required for using Portaudio
# PORTAUDIO_VERSION - Portaudio version
#
# Copyright (c) 2006 Andreas Schneider <mail@cynapses.org>
#
# Redistribution and use is allowed according to the terms of the New BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
#
if (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)
# in cache already
set(PORTAUDIO_FOUND TRUE)
else (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)
if (NOT WIN32)
include(FindPkgConfig)
pkg_check_modules(PORTAUDIO2 portaudio-2.0)
endif (NOT WIN32)
if (PORTAUDIO2_FOUND)
set(PORTAUDIO_INCLUDE_DIRS
${PORTAUDIO2_INCLUDE_DIRS}
)
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(PORTAUDIO_LIBRARIES "${PORTAUDIO2_LIBRARY_DIRS}/lib${PORTAUDIO2_LIBRARIES}.dylib")
else (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(PORTAUDIO_LIBRARIES
${PORTAUDIO2_LIBRARIES}
)
endif (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(PORTAUDIO_VERSION
19
)
set(PORTAUDIO_FOUND TRUE)
else (PORTAUDIO2_FOUND)
find_path(PORTAUDIO_INCLUDE_DIR
NAMES
portaudio.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
)
find_library(PORTAUDIO_LIBRARY
NAMES
portaudio
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
)
find_path(PORTAUDIO_LIBRARY_DIR
NAMES
portaudio
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
)
set(PORTAUDIO_INCLUDE_DIRS
${PORTAUDIO_INCLUDE_DIR}
)
set(PORTAUDIO_LIBRARIES
${PORTAUDIO_LIBRARY}
)
set(PORTAUDIO_LIBRARY_DIRS
${PORTAUDIO_LIBRARY_DIR}
)
set(PORTAUDIO_VERSION
18
)
if (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES)
set(PORTAUDIO_FOUND TRUE)
endif (PORTAUDIO_INCLUDE_DIRS AND PORTAUDIO_LIBRARIES)
if (PORTAUDIO_FOUND)
if (NOT Portaudio_FIND_QUIETLY)
message(STATUS "Found Portaudio: ${PORTAUDIO_LIBRARIES}")
endif (NOT Portaudio_FIND_QUIETLY)
else (PORTAUDIO_FOUND)
if (Portaudio_FIND_REQUIRED)
message(FATAL_ERROR "Could not find Portaudio")
else (Portaudio_FIND_REQUIRED)
message(STATUS "Could NOT find Portaudio")
endif (Portaudio_FIND_REQUIRED)
endif (PORTAUDIO_FOUND)
endif (PORTAUDIO2_FOUND)
# show the PORTAUDIO_INCLUDE_DIRS and PORTAUDIO_LIBRARIES variables only in the advanced view
mark_as_advanced(PORTAUDIO_INCLUDE_DIRS PORTAUDIO_LIBRARIES)
endif (PORTAUDIO_LIBRARIES AND PORTAUDIO_INCLUDE_DIRS)

19
dsd.h
View File

@ -42,6 +42,15 @@
#include "p25p1_heuristics.h" #include "p25p1_heuristics.h"
#define SAMPLE_RATE_IN 48000
#define SAMPLE_RATE_OUT 8000
#define PA_FRAMES_PER_BUFFER 64
#ifdef USE_PORTAUDIO
#include "portaudio.h"
#endif
/* /*
* global variables * global variables
*/ */
@ -66,12 +75,18 @@ typedef struct
int audio_in_fd; int audio_in_fd;
SNDFILE *audio_in_file; SNDFILE *audio_in_file;
SF_INFO *audio_in_file_info; SF_INFO *audio_in_file_info;
int audio_in_type; // 0 for device, 1 for file #ifdef USE_PORTAUDIO
PaStream* audio_in_pa_stream;
#endif
int audio_in_type; // 0 for device, 1 for file, 2 for portaudio
char audio_out_dev[1024]; char audio_out_dev[1024];
int audio_out_fd; int audio_out_fd;
SNDFILE *audio_out_file; SNDFILE *audio_out_file;
SF_INFO *audio_out_file_info; SF_INFO *audio_out_file_info;
int audio_out_type; // 0 for device, 1 for file #ifdef USE_PORTAUDIO
PaStream* audio_out_pa_stream;
#endif
int audio_out_type; // 0 for device, 1 for file, 2 for portaudio
int split; int split;
int playoffset; int playoffset;
char mbe_out_dir[1024]; char mbe_out_dir[1024];

View File

@ -17,6 +17,7 @@
#include "dsd.h" #include "dsd.h"
void void
processAudio (dsd_opts * opts, dsd_state * state) processAudio (dsd_opts * opts, dsd_state * state)
{ {
@ -213,16 +214,65 @@ writeSynthesizedVoice (dsd_opts * opts, dsd_state * state)
*/ */
} }
void void
playSynthesizedVoice (dsd_opts * opts, dsd_state * state) playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
{ {
ssize_t result; ssize_t result;
if (state->audio_out_idx > opts->delay) if (state->audio_out_idx > opts->delay)
{ {
// output synthesized speech to sound card // output synthesized speech to sound card
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2)); if(opts->audio_out_type == 2)
{
#ifdef USE_PORTAUDIO
PaError err = paNoError;
do
{
long available = Pa_GetStreamWriteAvailable( opts->audio_out_pa_stream );
if(available < 0)
err = available;
//printf("Frames available: %d\n", available);
if( err != paNoError )
break;
if(available > SAMPLE_RATE_OUT / 2)
{
printf("\nSyncing voice output stream\n");
err = Pa_StopStream( opts->audio_out_pa_stream );
if( err != paNoError )
break;
}
err = Pa_IsStreamActive( opts->audio_out_pa_stream );
if(err == 0)
{
printf("Start voice output stream\n");
err = Pa_StartStream( opts->audio_out_pa_stream );
}
else if(err == 1)
{
err = paNoError;
}
if( err != paNoError )
break;
//printf("write stream %d\n", state->audio_out_idx);
err = Pa_WriteStream( opts->audio_out_pa_stream, (state->audio_out_buf_p - state->audio_out_idx), state->audio_out_idx );
if( err != paNoError )
break;
} while(0);
if( err != paNoError )
{
fprintf( stderr, "An error occured while using the portaudio output stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
#endif
}
else
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
state->audio_out_idx = 0; state->audio_out_idx = 0;
} }
@ -236,11 +286,99 @@ playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
} }
} }
#ifdef USE_PORTAUDIO
int getPADevice(char* dev, int input, PaStream** stream)
{
int devnum = atoi(dev + 3);
printf("Using portaudio device %d.\n", devnum);
PaError err;
int numDevices = Pa_GetDeviceCount();
if( numDevices < 0 )
{
printf( "ERROR: Pa_GetDeviceCount returned 0x%x\n", numDevices );
err = numDevices;
goto error;
}
if( devnum >= numDevices)
{
printf( "ERROR: Requested device %d is larger than number of devices.\n", devnum );
return(1);
}
const PaDeviceInfo *deviceInfo = Pa_GetDeviceInfo( devnum );
/* print device name */
#ifdef WIN32
{ /* Use wide char on windows, so we can show UTF-8 encoded device names */
wchar_t wideName[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, deviceInfo->name, -1, wideName, MAX_PATH-1);
wprintf( L"Name = %s\n", wideName );
}
#else
printf( "Name = %s\n", deviceInfo->name );
#endif
if((input == 1) && (deviceInfo->maxInputChannels == 0))
{
printf( "ERROR: Requested device %d is not an input device.\n", devnum );
return(1);
}
if((input == 0) && (deviceInfo->maxOutputChannels == 0))
{
printf( "ERROR: Requested device %d is not an output device.\n", devnum );
return(1);
}
//Create stream parameters
PaStreamParameters parameters;
parameters.device = devnum;
parameters.channelCount = 1; /* mono */
parameters.sampleFormat = paInt16; //Shorts
parameters.suggestedLatency = 0.500; //0.050; // Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
parameters.hostApiSpecificStreamInfo = NULL;
//Open stream
err = Pa_OpenStream(
stream,
(input == 1) ? &parameters : NULL,
(input == 0) ? &parameters : NULL,
(input == 1) ? SAMPLE_RATE_IN : SAMPLE_RATE_OUT,
PA_FRAMES_PER_BUFFER,
paClipOff,
NULL /*callback*/,
NULL );
if( err != paNoError ) goto error;
return 0;
error:
fprintf( stderr, "An error occured while initializing a portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
}
#endif
void void
openAudioOutDevice (dsd_opts * opts, int speed) openAudioOutDevice (dsd_opts * opts, int speed)
{ {
// get info of device/file // get info of device/file
struct stat stat_buf; if(strncmp(opts->audio_in_dev, "pa:", 3) == 0)
{
opts->audio_out_type = 2;
#ifdef USE_PORTAUDIO
int err = getPADevice(opts->audio_out_dev, 0, &opts->audio_out_pa_stream);
if(err != 0)
exit(err);
#else
printf("Error, Portaudio support not compiled.\n");
exit(1);
#endif
}
else
{
struct stat stat_buf;
if(stat(opts->audio_out_dev, &stat_buf) != 0) if(stat(opts->audio_out_dev, &stat_buf) != 0)
{ {
printf("Error, couldn't open %s\n", opts->audio_out_dev); printf("Error, couldn't open %s\n", opts->audio_out_dev);
@ -316,6 +454,7 @@ openAudioOutDevice (dsd_opts * opts, int speed)
} }
#endif #endif
}
printf ("Audio Out Device: %s\n", opts->audio_out_dev); printf ("Audio Out Device: %s\n", opts->audio_out_dev);
} }
@ -323,6 +462,28 @@ void
openAudioInDevice (dsd_opts * opts) openAudioInDevice (dsd_opts * opts)
{ {
// get info of device/file // get info of device/file
if(strncmp(opts->audio_in_dev, "pa:", 2) == 0)
{
opts->audio_in_type = 2;
#ifdef USE_PORTAUDIO
int err = getPADevice(opts->audio_in_dev, 1, &opts->audio_in_pa_stream);
if(err != 0)
exit(err);
if (opts->split == 0)
{
int err = getPADevice(opts->audio_in_dev, 0, &opts->audio_out_pa_stream);
if(err != 0)
exit(err);
}
#else
printf("Error, Portaudio support not compiled.\n");
exit(1);
#endif
}
else
{
struct stat stat_buf; struct stat stat_buf;
if (stat(opts->audio_in_dev, &stat_buf) != 0) if (stat(opts->audio_in_dev, &stat_buf) != 0)
{ {
@ -370,8 +531,8 @@ openAudioInDevice (dsd_opts * opts)
// get current // get current
ioctl (opts->audio_in_fd, AUDIO_GETINFO, &aset); ioctl (opts->audio_in_fd, AUDIO_GETINFO, &aset);
aset.record.sample_rate = 48000; aset.record.sample_rate = SAMPLE_RATE_IN;
aset.play.sample_rate = 48000; aset.play.sample_rate = SAMPLE_RATE_IN;
aset.record.channels = 1; aset.record.channels = 1;
aset.play.channels = 1; aset.play.channels = 1;
aset.record.precision = 16; aset.record.precision = 16;
@ -411,7 +572,7 @@ openAudioInDevice (dsd_opts * opts)
{ {
printf ("ioctl reset error \n"); printf ("ioctl reset error \n");
} }
fmt = 48000; fmt = SAMPLE_RATE_IN;
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0) if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
{ {
printf ("ioctl speed error \n"); printf ("ioctl speed error \n");
@ -428,6 +589,8 @@ openAudioInDevice (dsd_opts * opts)
} }
#endif #endif
} }
}
if (opts->split == 1) if (opts->split == 1)
{ {
printf ("Audio In Device: %s\n", opts->audio_in_dev); printf ("Audio In Device: %s\n", opts->audio_in_dev);

View File

@ -27,6 +27,7 @@
#include "git_ver.h" #include "git_ver.h"
#include "p25p1_heuristics.h" #include "p25p1_heuristics.h"
int int
comp (const void *a, const void *b) comp (const void *a, const void *b)
{ {
@ -305,7 +306,20 @@ usage ()
void void
liveScanner (dsd_opts * opts, dsd_state * state) liveScanner (dsd_opts * opts, dsd_state * state)
{ {
while (1) #ifdef USE_PORTAUDIO
if(opts->audio_in_type == 2)
{
PaError err = Pa_StartStream( opts->audio_in_pa_stream );
if( err != paNoError )
{
fprintf( stderr, "An error occured while starting the portaudio input stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return;
}
}
#endif
while (1)
{ {
noCarrier (opts, state); noCarrier (opts, state);
state->synctype = getFrameSync (opts, state); state->synctype = getFrameSync (opts, state);
@ -344,6 +358,37 @@ cleanupAndExit (dsd_opts * opts, dsd_state * state)
closeWavOutFile (opts, state); closeWavOutFile (opts, state);
} }
#ifdef USE_PORTAUDIO
if((opts->audio_in_type == 2) || (opts->audio_out_type == 2))
{
printf("Terminating portaudio.\n");
PaError err = paNoError;
if(opts->audio_in_pa_stream != NULL)
err = Pa_CloseStream( opts->audio_in_pa_stream );
if( err != paNoError )
{
fprintf( stderr, "An error occured while closing the portaudio input stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
if(opts->audio_out_pa_stream != NULL)
err = Pa_CloseStream( opts->audio_out_pa_stream );
if( err != paNoError )
{
fprintf( stderr, "An error occured while closing the portaudio output stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
err = Pa_Terminate();
if( err != paNoError )
{
fprintf( stderr, "An error occured while terminating portaudio\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
}
#endif
printf("\n"); printf("\n");
printf("Total audio errors: %i\n", state->debug_audio_errors); printf("Total audio errors: %i\n", state->debug_audio_errors);
printf("Total header errors: %i\n", state->debug_header_errors); printf("Total header errors: %i\n", state->debug_header_errors);
@ -735,6 +780,23 @@ main (int argc, char **argv)
openSerial (&opts, &state); openSerial (&opts, &state);
} }
#ifdef USE_PORTAUDIO
if((strncmp(opts.audio_in_dev, "pa:", 3) == 0)
|| (strncmp(opts.audio_out_dev, "pa:", 3) == 0))
{
printf("Initializing portaudio.\n");
PaError err = Pa_Initialize();
if( err != paNoError )
{
fprintf( stderr, "An error occured while initializing portaudio\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
exit(err);
}
}
#endif
if (opts.playfiles == 1) if (opts.playfiles == 1)
{ {
opts.split = 1; opts.split = 1;
@ -746,7 +808,7 @@ main (int argc, char **argv)
} }
else else
{ {
openAudioOutDevice (&opts, 8000); openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
} }
} }
else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0) else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0)
@ -760,7 +822,7 @@ main (int argc, char **argv)
} }
else else
{ {
openAudioOutDevice (&opts, 8000); openAudioOutDevice (&opts, SAMPLE_RATE_OUT);
} }
openAudioInDevice (&opts); openAudioInDevice (&opts);
} }

View File

@ -82,12 +82,24 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
if(opts->audio_in_type == 0) { if(opts->audio_in_type == 0) {
result = read (opts->audio_in_fd, &sample, 2); result = read (opts->audio_in_fd, &sample, 2);
} }
else { else if (opts->audio_in_type == 1) {
result = sf_read_short(opts->audio_in_file, &sample, 1); result = sf_read_short(opts->audio_in_file, &sample, 1);
if(result == 0) { if(result == 0) {
cleanupAndExit (opts, state); cleanupAndExit (opts, state);
} }
} }
else
{
#ifdef USE_PORTAUDIO
PaError err = Pa_ReadStream( opts->audio_in_pa_stream, &sample, 1 );
if( err != paNoError )
{
fprintf( stderr, "An error occured while using the portaudio input stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
}
#endif
}
#ifdef TRACE_DSD #ifdef TRACE_DSD
state->debug_sample_index++; state->debug_sample_index++;
@ -267,8 +279,8 @@ getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
if (state->debug_label_file == NULL) { if (state->debug_label_file == NULL) {
state->debug_label_file = fopen ("pp_label.txt", "w"); state->debug_label_file = fopen ("pp_label.txt", "w");
} }
left = state->debug_sample_left_edge / 48000.0; left = state->debug_sample_left_edge / SAMPLE_RATE_IN;
right = state->debug_sample_right_edge / 48000.0; right = state->debug_sample_right_edge / SAMPLE_RATE_IN;
if (state->debug_prefix != '\0') { if (state->debug_prefix != '\0') {
if (state->debug_prefix == 'I') { if (state->debug_prefix == 'I') {
fprintf(state->debug_label_file, "%f\t%f\t%c%c %i\n", left, right, state->debug_prefix, state->debug_prefix_2, symbol); fprintf(state->debug_label_file, "%f\t%f\t%c%c %i\n", left, right, state->debug_prefix, state->debug_prefix_2, symbol);