From 6803965617e355f9e5f182cdc60eca75cecb19be Mon Sep 17 00:00:00 2001 From: robiwan Date: Wed, 22 Feb 2012 12:20:26 +0000 Subject: [PATCH] General: - Change of CMake options to utilize built in header configuration support (PA_USE_*) - Added CMakeLists.txt for examples - Added paex_ocean_shore.c as an example how to use PA ring buffer for lock-free communication with the audio callback WDM-KS: - Added better default sample rate support - Made sure that all pins now have a name, even if only "Input" or "Output" - IsUSBDevice fixed acc. to Alex Lessard's suggestion - IsNameUSBAudioDevice fixed similarly --- CMakeLists.txt | 147 +++++---- cmake_support/options_cmake.h.in | 10 +- examples/CMakeLists.txt | 20 ++ examples/paex_ocean_shore.c | 533 +++++++++++++++++++++++++++++++ src/hostapi/wdmks/pa_win_wdmks.c | 184 +++++++---- 5 files changed, 753 insertions(+), 141 deletions(-) create mode 100644 examples/CMakeLists.txt create mode 100644 examples/paex_ocean_shore.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 5852a2d..febdf2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,22 +7,22 @@ PROJECT( portaudio ) CMAKE_MINIMUM_REQUIRED(VERSION 2.8) -OPTION(PORTAUDIO_CONFIG_LIB_OUTPUT_PATH "Make sure that output paths are kept neat" OFF) +OPTION(PA_CONFIG_LIB_OUTPUT_PATH "Make sure that output paths are kept neat" OFF) IF(CMAKE_CL_64) SET(TARGET_POSTFIX x64) -IF(PORTAUDIO_CONFIG_LIB_OUTPUT_PATH) +IF(PA_CONFIG_LIB_OUTPUT_PATH) SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin/x64) -ENDIF(PORTAUDIO_CONFIG_LIB_OUTPUT_PATH) +ENDIF(PA_CONFIG_LIB_OUTPUT_PATH) ELSE(CMAKE_CL_64) SET(TARGET_POSTFIX x86) -IF(PORTAUDIO_CONFIG_LIB_OUTPUT_PATH) +IF(PA_CONFIG_LIB_OUTPUT_PATH) SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/bin/Win32) -ENDIF(PORTAUDIO_CONFIG_LIB_OUTPUT_PATH) +ENDIF(PA_CONFIG_LIB_OUTPUT_PATH) ENDIF(CMAKE_CL_64) IF(WIN32 AND MSVC) -OPTION(PORTAUDIO_DLL_LINK_WITH_STATIC_RUNTIME "Link with static runtime libraries (minimizes runtime dependencies)" ON) -IF(PORTAUDIO_DLL_LINK_WITH_STATIC_RUNTIME) +OPTION(PA_DLL_LINK_WITH_STATIC_RUNTIME "Link with static runtime libraries (minimizes runtime dependencies)" ON) +IF(PA_DLL_LINK_WITH_STATIC_RUNTIME) FOREACH(flag_var CMAKE_C_FLAGS CMAKE_C_FLAGS_DEBUG CMAKE_C_FLAGS_RELEASE CMAKE_C_FLAGS_MINSIZEREL CMAKE_C_FLAGS_RELWITHDEBINFO @@ -32,12 +32,12 @@ IF(PORTAUDIO_DLL_LINK_WITH_STATIC_RUNTIME) STRING(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") ENDIF(${flag_var} MATCHES "/MD") ENDFOREACH(flag_var) -ENDIF(PORTAUDIO_DLL_LINK_WITH_STATIC_RUNTIME) +ENDIF(PA_DLL_LINK_WITH_STATIC_RUNTIME) ENDIF(WIN32 AND MSVC) IF(WIN32) -OPTION(PORTAUDIO_UNICODE_BUILD "Enable Portaudio Unicode build" ON) +OPTION(PA_UNICODE_BUILD "Enable Portaudio Unicode build" ON) SET(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake_support) # Try to find DirectX SDK @@ -47,67 +47,57 @@ FIND_PACKAGE(DXSDK) FIND_PACKAGE(ASIOSDK) IF(ASIOSDK_FOUND) -OPTION(PORTAUDIO_ENABLE_ASIO "Enable support for ASIO" ON) +OPTION(PA_USE_ASIO "Enable support for ASIO" ON) ELSE(ASIOSDK_FOUND) -OPTION(PORTAUDIO_ENABLE_ASIO "Enable support for ASIO" OFF) +OPTION(PA_USE_ASIO "Enable support for ASIO" OFF) ENDIF(ASIOSDK_FOUND) IF(DXSDK_FOUND) -OPTION(PORTAUDIO_ENABLE_DSOUND "Enable support for DirectSound" ON) +OPTION(PA_USE_DS "Enable support for DirectSound" ON) ELSE(DXSDK_FOUND) -OPTION(PORTAUDIO_ENABLE_DSOUND "Enable support for DirectSound" OFF) +OPTION(PA_USE_DS "Enable support for DirectSound" OFF) ENDIF(DXSDK_FOUND) -OPTION(PORTAUDIO_ENABLE_WMME "Enable support for MME" ON) -OPTION(PORTAUDIO_ENABLE_WASAPI "Enable support for WASAPI" ON) -OPTION(PORTAUDIO_ENABLE_WDMKS "Enable support for WDMKS" ON) -OPTION(PORTAUDIO_USE_WDMKS_DEVICE_INFO "Use WDM/KS API for device info" ON) -MARK_AS_ADVANCED(PORTAUDIO_USE_WDMKS_DEVICE_INFO) -IF(PORTAUDIO_ENABLE_DSOUND) -OPTION(PORTAUDIO_USE_DIRECTSOUNDFULLDUPLEXCREATE "Use DirectSound full duplex create" ON) -MARK_AS_ADVANCED(PORTAUDIO_USE_DIRECTSOUNDFULLDUPLEXCREATE) -ENDIF(PORTAUDIO_ENABLE_DSOUND) +OPTION(PA_USE_WMME "Enable support for MME" ON) +OPTION(PA_USE_WASAPI "Enable support for WASAPI" ON) +OPTION(PA_USE_WDMKS "Enable support for WDMKS" ON) +OPTION(PA_USE_WDMKS_DEVICE_INFO "Use WDM/KS API for device info" ON) +MARK_AS_ADVANCED(PA_USE_WDMKS_DEVICE_INFO) +IF(PA_USE_DS) +OPTION(PA_USE_DIRECTSOUNDFULLDUPLEXCREATE "Use DirectSound full duplex create" ON) +MARK_AS_ADVANCED(PA_USE_DIRECTSOUNDFULLDUPLEXCREATE) +ENDIF(PA_USE_DS) ENDIF(WIN32) -MACRO(SET_HEADER_OPTION OPTION_NAME OPTION_VALUE) - IF(${OPTION_NAME}) - SET(${OPTION_VALUE} "1") - ELSE(${OPTION_NAME}) - SET(${OPTION_VALUE} "0") - ENDIF(${OPTION_NAME}) -ENDMACRO(SET_HEADER_OPTION) - -SET_HEADER_OPTION(PORTAUDIO_ENABLE_ASIO PA_ENABLE_ASIO) -SET_HEADER_OPTION(PORTAUDIO_ENABLE_DSOUND PA_ENABLE_DSOUND) -SET_HEADER_OPTION(PORTAUDIO_ENABLE_WMME PA_ENABLE_WMME) -SET_HEADER_OPTION(PORTAUDIO_ENABLE_WASAPI PA_ENABLE_WASAPI) -SET_HEADER_OPTION(PORTAUDIO_ENABLE_WDMKS PA_ENABLE_WDMKS) - # Set variables for DEF file expansion -IF(NOT PORTAUDIO_ENABLE_ASIO) +IF(NOT PA_USE_ASIO) SET(DEF_EXCLUDE_ASIO_SYMBOLS ";") -ENDIF(NOT PORTAUDIO_ENABLE_ASIO) +ENDIF(NOT PA_USE_ASIO) -IF(NOT PORTAUDIO_ENABLE_WASAPI) +IF(NOT PA_USE_WASAPI) SET(DEF_EXCLUDE_WASAPI_SYMBOLS ";") -ENDIF(NOT PORTAUDIO_ENABLE_WASAPI) +ENDIF(NOT PA_USE_WASAPI) -IF(PORTAUDIO_USE_WDMKS_DEVICE_INFO) +IF(PA_USE_WDMKS_DEVICE_INFO) ADD_DEFINITIONS(-DPAWIN_USE_WDMKS_DEVICE_INFO) -ENDIF(PORTAUDIO_USE_WDMKS_DEVICE_INFO) +ENDIF(PA_USE_WDMKS_DEVICE_INFO) -IF(PORTAUDIO_USE_DIRECTSOUNDFULLDUPLEXCREATE) +IF(PA_USE_DIRECTSOUNDFULLDUPLEXCREATE) ADD_DEFINITIONS(-DPAWIN_USE_DIRECTSOUNDFULLDUPLEXCREATE) -ENDIF(PORTAUDIO_USE_DIRECTSOUNDFULLDUPLEXCREATE) +ENDIF(PA_USE_DIRECTSOUNDFULLDUPLEXCREATE) ####################################### IF(WIN32) INCLUDE_DIRECTORIES(src/os/win) ENDIF(WIN32) -IF(PORTAUDIO_ENABLE_ASIO) +IF(PA_USE_ASIO) INCLUDE_DIRECTORIES(${ASIOSDK_ROOT_DIR}/common) INCLUDE_DIRECTORIES(${ASIOSDK_ROOT_DIR}/host) INCLUDE_DIRECTORIES(${ASIOSDK_ROOT_DIR}/host/pc) +SET(PA_ASIO_INCLUDES + include/pa_asio.h +) + SET(PA_ASIO_SOURCES src/hostapi/asio/pa_asio.cpp ) @@ -125,13 +115,14 @@ SOURCE_GROUP("hostapi\\ASIO" FILES SOURCE_GROUP("hostapi\\ASIO\\ASIOSDK" FILES ${PA_ASIOSDK_SOURCES} ) -ENDIF(PORTAUDIO_ENABLE_ASIO) +ENDIF(PA_USE_ASIO) -IF(PORTAUDIO_ENABLE_DSOUND) +IF(PA_USE_DS) INCLUDE_DIRECTORIES(${DXSDK_INCLUDE_DIR}) INCLUDE_DIRECTORIES(src/os/win) SET(PA_DS_INCLUDES + include/pa_win_ds.h src/hostapi/dsound/pa_win_ds_dynlink.h ) @@ -144,9 +135,14 @@ SOURCE_GROUP("hostapi\\dsound" FILES ${PA_DS_INCLUDES} ${PA_DS_SOURCES} ) -ENDIF(PORTAUDIO_ENABLE_DSOUND) +ENDIF(PA_USE_DS) + +IF(PA_USE_WMME) + +SET(PA_WMME_INCLUDES + include/pa_win_wmme.h +) -IF(PORTAUDIO_ENABLE_WMME) SET(PA_WMME_SOURCES src/hostapi/wmme/pa_win_wmme.c ) @@ -154,9 +150,14 @@ SET(PA_WMME_SOURCES SOURCE_GROUP("hostapi\\wmme" FILES ${PA_WMME_SOURCES} ) -ENDIF(PORTAUDIO_ENABLE_WMME) +ENDIF(PA_USE_WMME) + +IF(PA_USE_WASAPI) + +SET(PA_WASAPI_INCLUDES + include/pa_win_wasapi.h +) -IF(PORTAUDIO_ENABLE_WASAPI) SET(PA_WASAPI_SOURCES src/hostapi/wasapi/pa_win_wasapi.c ) @@ -164,9 +165,14 @@ SET(PA_WASAPI_SOURCES SOURCE_GROUP("hostapi\\wasapi" FILES ${PA_WASAPI_SOURCES} ) -ENDIF(PORTAUDIO_ENABLE_WASAPI) +ENDIF(PA_USE_WASAPI) + +IF(PA_USE_WDMKS) + +SET(PA_WDMKS_INCLUDES + include/pa_win_wdmks.h +) -IF(PORTAUDIO_ENABLE_WDMKS) SET(PA_WDMKS_SOURCES src/hostapi/wdmks/pa_win_wdmks.c ) @@ -174,7 +180,7 @@ SET(PA_WDMKS_SOURCES SOURCE_GROUP("hostapi\\wdmks" FILES ${PA_WDMKS_SOURCES} ) -ENDIF(PORTAUDIO_ENABLE_WDMKS) +ENDIF(PA_USE_WDMKS) SET(PA_SKELETON_SOURCES src/hostapi/skeleton/pa_hostapi_skeleton.c @@ -187,10 +193,11 @@ SOURCE_GROUP("hostapi\\skeleton" IF(WIN32) SET(PA_INCLUDES include/portaudio.h - include/pa_asio.h - include/pa_win_ds.h - include/pa_win_wasapi.h - include/pa_win_wmme.h + ${PA_ASIO_INCLUDES} + ${PA_DS_INCLUDES} + ${PA_WMME_INCLUDES} + ${PA_WASAPI_INCLUDES} + ${PA_WDMKS_INCLUDES} ) ENDIF(WIN32) @@ -274,13 +281,13 @@ SET(SOURCES_LESS_ASIO_SDK ${PA_PLATFORM_SOURCES} ) -IF(PORTAUDIO_UNICODE_BUILD) +IF(PA_UNICODE_BUILD) SET_SOURCE_FILES_PROPERTIES( ${SOURCES_LESS_ASIO_SDK} PROPERTIES COMPILE_DEFINITIONS "UNICODE;_UNICODE" ) -ENDIF(PORTAUDIO_UNICODE_BUILD) +ENDIF(PA_UNICODE_BUILD) ADD_LIBRARY(portaudio SHARED ${PA_INCLUDES} @@ -307,25 +314,31 @@ CONFIGURE_FILE( cmake_support/options_cmake.h.in ${CMAKE_CURRENT_BINARY_DIR}/opt IF(WIN32) # If we use DirectSound, we need this for the library to be found (if not in VS project settings) -IF(PORTAUDIO_ENABLE_DSOUND AND DXSDK_FOUND) +IF(PA_USE_DS AND DXSDK_FOUND) TARGET_LINK_LIBRARIES(portaudio ${DXSDK_DSOUND_LIBRARY}) -ENDIF(PORTAUDIO_ENABLE_DSOUND AND DXSDK_FOUND) +ENDIF(PA_USE_DS AND DXSDK_FOUND) # If we use WDM/KS we need setupapi.lib -IF(PORTAUDIO_ENABLE_WDMKS) +IF(PA_USE_WDMKS) TARGET_LINK_LIBRARIES(portaudio setupapi) -ENDIF(PORTAUDIO_ENABLE_WDMKS) +ENDIF(PA_USE_WDMKS) SET_TARGET_PROPERTIES(portaudio PROPERTIES OUTPUT_NAME portaudio_${TARGET_POSTFIX}) SET_TARGET_PROPERTIES(portaudio_static PROPERTIES OUTPUT_NAME portaudio_static_${TARGET_POSTFIX}) ENDIF(WIN32) -OPTION(PORTAUDIO_BUILD_TESTS "Include test projects" OFF) +OPTION(PA_BUILD_TESTS "Include test projects" OFF) +OPTION(PA_BUILD_EXAMPLES "Include example projects" OFF) # Prepared for inclusion of test files -IF(PORTAUDIO_BUILD_TESTS) +IF(PA_BUILD_TESTS) SUBDIRS(test) -ENDIF(PORTAUDIO_BUILD_TESTS) +ENDIF(PA_BUILD_TESTS) + +# Prepared for inclusion of test files +IF(PA_BUILD_EXAMPLES) +SUBDIRS(examples) +ENDIF(PA_BUILD_EXAMPLES) ################################# diff --git a/cmake_support/options_cmake.h.in b/cmake_support/options_cmake.h.in index 06d7dcd..8308bb7 100644 --- a/cmake_support/options_cmake.h.in +++ b/cmake_support/options_cmake.h.in @@ -21,11 +21,11 @@ #error "This header needs to be included before pa_hostapi.h!!" #endif -#define PA_USE_ASIO @PA_ENABLE_ASIO@ -#define PA_USE_DS @PA_ENABLE_DSOUND@ -#define PA_USE_WMME @PA_ENABLE_WMME@ -#define PA_USE_WASAPI @PA_ENABLE_WASAPI@ -#define PA_USE_WDMKS @PA_ENABLE_WDMKS@ +#cmakedefine01 PA_USE_ASIO +#cmakedefine01 PA_USE_DS +#cmakedefine01 PA_USE_WMME +#cmakedefine01 PA_USE_WASAPI +#cmakedefine01 PA_USE_WDMKS #else #error "Platform currently not supported by CMake script" #endif diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..72247ea --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,20 @@ +# Example projects + +MACRO(ADD_EXAMPLE appl_name) + ADD_EXECUTABLE(${appl_name} "${appl_name}.c") + TARGET_LINK_LIBRARIES(${appl_name} portaudio_static) +ENDMACRO(ADD_EXAMPLE) + +ADD_EXAMPLE(pa_devs) +ADD_EXAMPLE(pa_fuzz) +ADD_EXAMPLE(paex_mono_asio_channel_select) +ADD_EXAMPLE(paex_ocean_shore) +ADD_EXAMPLE(paex_pink) +ADD_EXAMPLE(paex_read_write_wire) +ADD_EXAMPLE(paex_record) +ADD_EXAMPLE(paex_saw) +ADD_EXAMPLE(paex_sine) +ADD_EXAMPLE(paex_wmme_ac3) +ADD_EXAMPLE(paex_wmme_surround) +ADD_EXAMPLE(paex_write_sine) +ADD_EXAMPLE(paex_write_sine_nonint) diff --git a/examples/paex_ocean_shore.c b/examples/paex_ocean_shore.c new file mode 100644 index 0000000..42e2b55 --- /dev/null +++ b/examples/paex_ocean_shore.c @@ -0,0 +1,533 @@ +/** @file paex_ocean_shore.c + @ingroup examples_src + @brief Generate Pink Noise using Gardner method, and make "waves". Provides an example of how to + post stuff to/from the audio callback using lock-free FIFOs implemented by the PA ringbuffer. + + Optimization suggested by James McCartney uses a tree + to select which random value to replace. +
+	x x x x x x x x x x x x x x x x 
+	x   x   x   x   x   x   x   x   
+	x       x       x       x       
+	 x               x               
+	   x   
+
+ Tree is generated by counting trailing zeros in an increasing index. + When the index is zero, no random number is selected. + + @author Phil Burk http://www.softsynth.com + Robert Bielik +*/ +/* + * $Id$ + * + * This program uses the PortAudio Portable Audio Library. + * For more information see: http://www.portaudio.com + * Copyright (c) 1999-2000 Ross Bencina and Phil Burk + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * The text above constitutes the entire PortAudio license; however, + * the PortAudio community also makes the following non-binding requests: + * + * Any person wishing to distribute modifications to the Software is + * requested to send the modifications to the original developer so that + * they can be incorporated into the canonical version. It is also + * requested that these non-binding requests be included along with the + * license above. + */ + +#include +#include +#include +#include +#include + +#include "portaudio.h" +#include "pa_ringbuffer.h" +#include "pa_util.h" + +#define PINK_MAX_RANDOM_ROWS (30) +#define PINK_RANDOM_BITS (24) +#define PINK_RANDOM_SHIFT ((sizeof(long)*8)-PINK_RANDOM_BITS) + +typedef struct +{ + long pink_Rows[PINK_MAX_RANDOM_ROWS]; + long pink_RunningSum; /* Used to optimize summing of generators. */ + int pink_Index; /* Incremented each sample. */ + int pink_IndexMask; /* Index wrapped by ANDing with this mask. */ + float pink_Scalar; /* Used to scale within range of -1.0 to +1.0 */ +} +PinkNoise; + +typedef struct +{ + float bq_b0; + float bq_b1; + float bq_b2; + float bq_a1; + float bq_a2; +} BiQuad; + +typedef enum +{ + State_kAttack, + State_kPreDecay, + State_kDecay, + State_kCnt, +} EnvState; + +typedef struct +{ + PinkNoise wave_left; + PinkNoise wave_right; + + BiQuad wave_bq_coeffs; + float wave_bq_left[2]; + float wave_bq_right[2]; + + EnvState wave_envelope_state; + float wave_envelope_level; + float wave_envelope_max_level; + float wave_pan_left; + float wave_pan_right; + float wave_attack_incr; + float wave_decay_incr; + +} OceanWave; + +/* Prototypes */ +static unsigned long GenerateRandomNumber( void ); +void InitializePinkNoise( PinkNoise *pink, int numRows ); +float GeneratePinkNoise( PinkNoise *pink ); +unsigned GenerateWave( OceanWave* wave, float* output, unsigned noOfFrames); + +/************************************************************/ +/* Calculate pseudo-random 32 bit number based on linear congruential method. */ +static unsigned long GenerateRandomNumber( void ) +{ + /* Change this seed for different random sequences. */ + static unsigned long randSeed = 22222; + randSeed = (randSeed * 196314165) + 907633515; + return randSeed; +} + +/************************************************************/ +/* Setup PinkNoise structure for N rows of generators. */ +void InitializePinkNoise( PinkNoise *pink, int numRows ) +{ + int i; + long pmax; + pink->pink_Index = 0; + pink->pink_IndexMask = (1<pink_Scalar = 1.0f / pmax; + /* Initialize rows. */ + for( i=0; ipink_Rows[i] = 0; + pink->pink_RunningSum = 0; +} + +/* Generate Pink noise values between -1.0 and +1.0 */ +float GeneratePinkNoise( PinkNoise *pink ) +{ + long newRandom; + long sum; + float output; + /* Increment and mask index. */ + pink->pink_Index = (pink->pink_Index + 1) & pink->pink_IndexMask; + /* If index is zero, don't update any random values. */ + if( pink->pink_Index != 0 ) + { + /* Determine how many trailing zeros in PinkIndex. */ + /* This algorithm will hang if n==0 so test first. */ + int numZeros = 0; + int n = pink->pink_Index; + while( (n & 1) == 0 ) + { + n = n >> 1; + numZeros++; + } + /* Replace the indexed ROWS random value. + * Subtract and add back to RunningSum instead of adding all the random + * values together. Only one changes each time. + */ + pink->pink_RunningSum -= pink->pink_Rows[numZeros]; + newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; + pink->pink_RunningSum += newRandom; + pink->pink_Rows[numZeros] = newRandom; + } + + /* Add extra white noise value. */ + newRandom = ((long)GenerateRandomNumber()) >> PINK_RANDOM_SHIFT; + sum = pink->pink_RunningSum + newRandom; + /* Scale to range of -1.0 to 0.9999. */ + output = pink->pink_Scalar * sum; + return output; +} + +float ProcessBiquad(const BiQuad* coeffs, float* memory, float input) +{ + float w = input - coeffs->bq_a1 * memory[0] - coeffs->bq_a2 * memory[1]; + float out = coeffs->bq_b1 * memory[0] + coeffs->bq_b2 * memory[1] + coeffs->bq_b0 * w; + memory[1] = memory[0]; + memory[0] = w; + return out; +} + +static const float one_over_2Q_LP = 0.3f; +static const float one_over_2Q_HP = 1.0f; + +unsigned GenerateWave( OceanWave* wave, float* output, unsigned noOfFrames ) +{ + unsigned retval=0,i; + float targetLevel, levelIncr, currentLevel; + switch (wave->wave_envelope_state) + { + case State_kAttack: + targetLevel = noOfFrames * wave->wave_attack_incr + wave->wave_envelope_level; + if (targetLevel >= wave->wave_envelope_max_level) + { + /* Go to decay state */ + wave->wave_envelope_state = State_kPreDecay; + targetLevel = wave->wave_envelope_max_level; + } + /* Calculate lowpass biquad coeffs + + alpha = sin(w0)/(2*Q) + + b0 = (1 - cos(w0))/2 + b1 = 1 - cos(w0) + b2 = (1 - cos(w0))/2 + a0 = 1 + alpha + a1 = -2*cos(w0) + a2 = 1 - alpha + + w0 = [0 - pi[ + */ + { + const float w0 = 3.141592654f * targetLevel / wave->wave_envelope_max_level; + const float alpha = sinf(w0) * one_over_2Q_LP; + const float cosw0 = cosf(w0); + const float a0_fact = 1.0f / (1.0f + alpha); + wave->wave_bq_coeffs.bq_b1 = (1.0f - cosw0) * a0_fact; + wave->wave_bq_coeffs.bq_b0 = wave->wave_bq_coeffs.bq_b1 * 0.5f; + wave->wave_bq_coeffs.bq_b2 = wave->wave_bq_coeffs.bq_b0; + wave->wave_bq_coeffs.bq_a2 = (1.0f - alpha) * a0_fact; + wave->wave_bq_coeffs.bq_a1 = -2.0f * cosw0 * a0_fact; + } + break; + + case State_kPreDecay: + /* Reset biquad state */ + memset(wave->wave_bq_left, 0, 2 * sizeof(float)); + memset(wave->wave_bq_right, 0, 2 * sizeof(float)); + wave->wave_envelope_state = State_kDecay; + + /* Deliberate fall-through */ + + case State_kDecay: + targetLevel = noOfFrames * wave->wave_decay_incr + wave->wave_envelope_level; + if (targetLevel < 0.001f) + { + /* < -60 dB, we're done */ + wave->wave_envelope_state = 3; + retval = 1; + } + /* Calculate highpass biquad coeffs + + alpha = sin(w0)/(2*Q) + + b0 = (1 + cos(w0))/2 + b1 = -(1 + cos(w0)) + b2 = (1 + cos(w0))/2 + a0 = 1 + alpha + a1 = -2*cos(w0) + a2 = 1 - alpha + + w0 = [0 - pi/2[ + */ + { + const float v = targetLevel / wave->wave_envelope_max_level; + const float w0 = 1.5707963f * (1.0f - (v*v)); + const float alpha = sinf(w0) * one_over_2Q_HP; + const float cosw0 = cosf(w0); + const float a0_fact = 1.0f / (1.0f + alpha); + wave->wave_bq_coeffs.bq_b1 = (float)(- (1 + cosw0) * a0_fact); + wave->wave_bq_coeffs.bq_b0 = -wave->wave_bq_coeffs.bq_b1 * 0.5f; + wave->wave_bq_coeffs.bq_b2 = wave->wave_bq_coeffs.bq_b0; + wave->wave_bq_coeffs.bq_a2 = (float)((1.0 - alpha) * a0_fact); + wave->wave_bq_coeffs.bq_a1 = (float)(-2.0 * cosw0 * a0_fact); + } + break; + + default: + break; + } + + currentLevel = wave->wave_envelope_level; + wave->wave_envelope_level = targetLevel; + levelIncr = (targetLevel - currentLevel) / noOfFrames; + + for (i = 0; i < noOfFrames; ++i, currentLevel += levelIncr) + { + (*output++) += ProcessBiquad(&wave->wave_bq_coeffs, wave->wave_bq_left, (GeneratePinkNoise(&wave->wave_left))) * currentLevel * wave->wave_pan_left; + (*output++) += ProcessBiquad(&wave->wave_bq_coeffs, wave->wave_bq_right, (GeneratePinkNoise(&wave->wave_right))) * currentLevel * wave->wave_pan_right; + } + + return retval; +} + + +/*******************************************************************/ + +/* Context for callback routine. */ +typedef struct +{ + OceanWave* waves[16]; /* Maximum 16 waves */ + unsigned noOfActiveWaves; + + /* Ring buffer (FIFO) for "communicating" towards audio callback */ + PaUtilRingBuffer rBufToRT; + void* rBufToRTData; + + /* Ring buffer (FIFO) for "communicating" from audio callback */ + PaUtilRingBuffer rBufFromRT; + void* rBufFromRTData; +} +paTestData; + +/* This routine will be called by the PortAudio engine when audio is needed. +** It may called at interrupt level on some machines so don't do anything +** that could mess up the system like calling malloc() or free(). +*/ +static int patestCallback(const void* inputBuffer, + void* outputBuffer, + unsigned long framesPerBuffer, + const PaStreamCallbackTimeInfo* timeInfo, + PaStreamCallbackFlags statusFlags, + void* userData) +{ + int i; + paTestData *data = (paTestData*)userData; + float *out = (float*)outputBuffer; + (void) inputBuffer; /* Prevent "unused variable" warnings. */ + + /* Reset output data first */ + memset(out, 0, framesPerBuffer * 2 * sizeof(float)); + + for (i = 0; i < 16; ++i) + { + /* Consume the input queue */ + if (data->waves[i] == 0 && PaUtil_GetRingBufferReadAvailable(&data->rBufToRT)) + { + OceanWave* ptr = 0; + PaUtil_ReadRingBuffer(&data->rBufToRT, &ptr, 1); + data->waves[i] = ptr; + } + + if (data->waves[i] != 0) + { + if (GenerateWave(data->waves[i], out, framesPerBuffer)) + { + /* If wave is "done", post it back to the main thread for deletion */ + PaUtil_WriteRingBuffer(&data->rBufFromRT, &data->waves[i], 1); + data->waves[i] = 0; + } + } + } + return paContinue; +} + +#define NEW_ROW_SIZE (12 + (8*rand())/RAND_MAX) + +OceanWave* InitializeWave(double SR, float attackInSeconds, float maxLevel, float positionLeftRight) +{ + OceanWave* wave = NULL; + static unsigned lastNoOfRows = 12; + unsigned newNoOfRows; + + wave = (OceanWave*)PaUtil_AllocateMemory(sizeof(OceanWave)); + if (wave != NULL) + { + InitializePinkNoise(&wave->wave_left, lastNoOfRows); + while ((newNoOfRows = NEW_ROW_SIZE) == lastNoOfRows); + InitializePinkNoise(&wave->wave_right, newNoOfRows); + lastNoOfRows = newNoOfRows; + + wave->wave_envelope_state = State_kAttack; + wave->wave_envelope_level = 0.f; + wave->wave_envelope_max_level = maxLevel; + wave->wave_attack_incr = wave->wave_envelope_max_level / (attackInSeconds * (float)SR); + wave->wave_decay_incr = - wave->wave_envelope_max_level / (attackInSeconds * 4 * (float)SR); + + wave->wave_pan_left = sqrtf(1.0 - positionLeftRight); + wave->wave_pan_right = sqrtf(positionLeftRight); + } + return wave; +} + +static float GenerateFloatRandom(float minValue, float maxValue) +{ + return minValue + ((maxValue - minValue) * rand()) / RAND_MAX; +} + +/*******************************************************************/ +int main(void); +int main(void) +{ + PaStream* stream; + PaError err; + paTestData data = {0}; + PaStreamParameters outputParameters; + double tstamp; + double tstart; + double tdelta = 0; + static const double SR = 44100.0; + static const int FPB = 128; /* Frames per buffer: 2.9 ms buffers. */ + + /* Initialize communication buffers (queues) */ + data.rBufToRTData = PaUtil_AllocateMemory(sizeof(OceanWave*) * 256); + if (data.rBufToRTData == NULL) + { + return 1; + } + PaUtil_InitializeRingBuffer(&data.rBufToRT, sizeof(OceanWave*), 256, data.rBufToRTData); + + data.rBufFromRTData = PaUtil_AllocateMemory(sizeof(OceanWave*) * 256); + if (data.rBufFromRTData == NULL) + { + return 1; + } + PaUtil_InitializeRingBuffer(&data.rBufFromRT, sizeof(OceanWave*), 256, data.rBufFromRTData); + + err = Pa_Initialize(); + if( err != paNoError ) goto error; + + /* Open a stereo PortAudio stream so we can hear the result. */ + outputParameters.device = Pa_GetDefaultOutputDevice(); /* Take the default output device. */ + if (outputParameters.device == paNoDevice) { + fprintf(stderr,"Error: No default output device.\n"); + goto error; + } + outputParameters.channelCount = 2; /* Stereo output, most likely supported. */ + outputParameters.hostApiSpecificStreamInfo = NULL; + outputParameters.sampleFormat = paFloat32; /* 32 bit floating point output. */ + outputParameters.suggestedLatency = Pa_GetDeviceInfo(outputParameters.device)->defaultLowOutputLatency; + err = Pa_OpenStream(&stream, + NULL, /* No input. */ + &outputParameters, + SR, /* Sample rate. */ + FPB, /* Frames per buffer. */ + paDitherOff, /* Clip but don't dither */ + patestCallback, + &data); + if( err != paNoError ) goto error; + + err = Pa_StartStream( stream ); + if( err != paNoError ) goto error; + + printf("Stereo \"ocean waves\" for one minute...\n"); + + tstart = PaUtil_GetTime(); + tstamp = tstart; + srand( (unsigned)time(NULL) ); + + while( ( err = Pa_IsStreamActive( stream ) ) == 1 ) + { + const double tcurrent = PaUtil_GetTime(); + + /* Delete "waves" that the callback is finished with */ + while (PaUtil_GetRingBufferReadAvailable(&data.rBufFromRT) > 0) + { + OceanWave* ptr = 0; + PaUtil_ReadRingBuffer(&data.rBufFromRT, &ptr, 1); + if (ptr != 0) + { + printf("Wave is deleted...\n"); + PaUtil_FreeMemory(ptr); + --data.noOfActiveWaves; + } + } + + if (tcurrent - tstart < 60.0) /* Only start new "waves" during one minute */ + { + if (tcurrent >= tstamp) + { + double tdelta = GenerateFloatRandom(1.0f, 4.0f); + tstamp += tdelta; + + if (data.noOfActiveWaves<16) + { + const float attackTime = GenerateFloatRandom(2.0f, 6.0f); + const float level = GenerateFloatRandom(0.1f, 1.0f); + const float pos = GenerateFloatRandom(0.0f, 1.0f); + OceanWave* p = InitializeWave(SR, attackTime, level, pos); + if (p != NULL) + { + /* Post wave to audio callback */ + PaUtil_WriteRingBuffer(&data.rBufToRT, &p, 1); + ++data.noOfActiveWaves; + + printf("Starting wave at level = %.2f, attack = %.2lf, pos = %.2lf\n", level, attackTime, pos); + } + } + } + } + else + { + if (data.noOfActiveWaves == 0) + { + printf("All waves finished!\n"); + break; + } + } + + Pa_Sleep(100); + } + if( err < 0 ) goto error; + + err = Pa_CloseStream( stream ); + if( err != paNoError ) goto error; + + if (data.rBufToRTData) + { + PaUtil_FreeMemory(data.rBufToRTData); + } + if (data.rBufFromRTData) + { + PaUtil_FreeMemory(data.rBufFromRTData); + } + + Pa_Sleep(1000); + + Pa_Terminate(); + return 0; + +error: + Pa_Terminate(); + fprintf( stderr, "An error occured while using the portaudio stream\n" ); + fprintf( stderr, "Error number: %d\n", err ); + fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) ); + return 0; +} diff --git a/src/hostapi/wdmks/pa_win_wdmks.c b/src/hostapi/wdmks/pa_win_wdmks.c index 684654d..515e790 100644 --- a/src/hostapi/wdmks/pa_win_wdmks.c +++ b/src/hostapi/wdmks/pa_win_wdmks.c @@ -257,7 +257,7 @@ struct __PaWinWdmPin unsigned long frameSize; int maxChannels; unsigned long formats; - int bestSampleRate; + int defaultSampleRate; ULONG *positionRegister; /* WaveRT */ ULONG hwLatency; /* WaveRT */ FunctionMemoryBarrier fnMemBarrier; /* WaveRT */ @@ -1217,6 +1217,44 @@ static PaError GetNameFromCategory(const GUID* pGUID, BOOL input, wchar_t* name, return result; } +static BOOL IsFrequencyWithinRange(const KSDATARANGE_AUDIO* range, int frequency) +{ + if (frequency < (int)range->MinimumSampleFrequency) + return FALSE; + if (frequency > (int)range->MaximumSampleFrequency) + return FALSE; + return TRUE; +} + +static BOOL IsBitsWithinRange(const KSDATARANGE_AUDIO* range, int noOfBits) +{ + if (noOfBits < (int)range->MinimumBitsPerSample) + return FALSE; + if (noOfBits > (int)range->MaximumBitsPerSample) + return FALSE; + return TRUE; +} + +static int SearchDefaultSampleFrequency(const KSDATARANGE_AUDIO* range) +{ + /* Note: Somewhat different order compared to WMME implementation, as we want to focus on fidelity first */ + static const int defaultSampleRateSearchOrder[] = + { 44100, 48000, 88200, 96000, 192000, 32000, 24000, 22050, 16000, 12000, 11025, 9600, 8000 }; + static const int defaultSampleRateSearchOrderCount = sizeof(defaultSampleRateSearchOrder)/sizeof(defaultSampleRateSearchOrder[0]); + int i; + + for(i=0; i < defaultSampleRateSearchOrderCount; ++i) + { + int currentFrequency = defaultSampleRateSearchOrder[i]; + + if (IsFrequencyWithinRange(range, currentFrequency)) + { + return currentFrequency; + } + } + + return 0; +} /* Create a new pin object belonging to a filter @@ -1398,7 +1436,7 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa result = paUnanticipatedHostError; dataRange = pin->dataRanges; pin->maxChannels = 0; - pin->bestSampleRate = 0; + pin->defaultSampleRate = 0; pin->formats = 0; PA_DEBUG(("PinNew: Checking %u no of dataranges...\n", pin->dataRangesItem->Count)); for( i = 0; i < pin->dataRangesItem->Count; i++) @@ -1424,26 +1462,22 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa PA_DEBUG(("PinNew: MaxChannel: %d\n",pin->maxChannels)); /* Record the formats (bit depths) that are supported */ - if( ((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 8 && - ((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 8) + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 8) ) { pin->formats |= paInt8; PA_DEBUG(("PinNew: Format PCM 8 bit supported\n")); } - if( ((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 16 && - ((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 16) + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 16) ) { pin->formats |= paInt16; PA_DEBUG(("PinNew: Format PCM 16 bit supported\n")); } - if( ((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 24 && - ((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 24 ) + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 24) ) { pin->formats |= paInt24; PA_DEBUG(("PinNew: Format PCM 24 bit supported\n")); } - if( ((KSDATARANGE_AUDIO*)dataRange)->MinimumBitsPerSample <= 32 && - ((KSDATARANGE_AUDIO*)dataRange)->MaximumBitsPerSample >= 32 ) + if( IsBitsWithinRange((KSDATARANGE_AUDIO*)dataRange, 32) ) { if (IsEqualGUID(&dataRange->SubFormat, &KSDATAFORMAT_SUBTYPE_IEEE_FLOAT)) { @@ -1456,23 +1490,11 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa PA_DEBUG(("PinNew: Format PCM 32 bit supported\n")); } } - if( ( pin->bestSampleRate != 48000) && - (((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 48000) && - (((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 48000) ) - { - pin->bestSampleRate = 48000; - PA_DEBUG(("PinNew: 48kHz supported\n")); - } - else if(( pin->bestSampleRate != 48000) && ( pin->bestSampleRate != 44100 ) && - (((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency >= 44100) && - (((KSDATARANGE_AUDIO*)dataRange)->MinimumSampleFrequency <= 44100) ) - { - pin->bestSampleRate = 44100; - PA_DEBUG(("PinNew: 44.1kHz supported\n")); - } - else + + if (pin->defaultSampleRate == 0) { - pin->bestSampleRate = ((KSDATARANGE_AUDIO*)dataRange)->MaximumSampleFrequency; + pin->defaultSampleRate = SearchDefaultSampleFrequency((KSDATARANGE_AUDIO*)dataRange); + PA_DEBUG(("PinNew: Default sample rate = %d Hz\n", pin->defaultSampleRate)); } } dataRange = (KSDATARANGE*)( ((char*)dataRange) + dataRange->FormatSize); @@ -1555,6 +1577,17 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa } } + /* Make sure pin gets a name here... */ + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, (pin->dataFlow == KSPIN_DATAFLOW_IN) ? L"Output" : L"Input"); +#ifdef UNICODE + PA_DEBUG(("PinNew: Setting pin friendly name to '%s'\n", pin->friendlyName)); +#else + PA_DEBUG(("PinNew: Setting pin friendly name to '%S'\n", pin->friendlyName)); +#endif + } + /* This is then == the endpoint pin */ pin->endpointPinId = (pin->dataFlow == KSPIN_DATAFLOW_IN) ? pinId : topoPinId; } @@ -1658,25 +1691,28 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa if (result == paNoError && wcslen(pinName)>0) { - wcstombs(pin->friendlyName, pinName, MAX_PATH); + wcsncpy(pin->friendlyName, pinName, MAX_PATH); } else #endif { result = GetNameFromCategory(&category, (pin->dataFlow == KSPIN_DATAFLOW_OUT), pin->friendlyName, MAX_PATH); - - if (result != paNoError) - { - wcscpy(pin->friendlyName, L"Output"); - } } + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, L"Output"); + } +#ifdef UNICODE + PA_DEBUG(("PinNew: Pin name '%s'\n", pin->friendlyName)); +#else PA_DEBUG(("PinNew: Pin name '%S'\n", pin->friendlyName)); +#endif } /* Set endpoint pin ID (this is the topology INPUT pin, since portmixer will always traverse the filter in audio streaming direction, see http://msdn.microsoft.com/en-us/library/windows/hardware/ff536331(v=vs.85).aspx - for more information. + for more information) */ pin->endpointPinId = pc->Pin; } @@ -1736,11 +1772,6 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa if (result != paNoError) { result = GetNameFromCategory(&category, TRUE, pin->friendlyName, MAX_PATH); - - if( result != paNoError ) - { - wcscpy(pin->friendlyName, L"Input"); - } } break; } @@ -1754,12 +1785,26 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa } } } + else + { + PA_DEBUG(("PinNew: Failed to get pin category")); + } } } if (muxCount == 0) { pin->endpointPinId = endpointPinId; + /* Make sure we get a name for the pin */ + if (wcslen(pin->friendlyName) == 0) + { + wcscpy(pin->friendlyName, L"Input"); + } +#ifdef UNICODE + PA_DEBUG(("PinNew: Input friendly name '%s'\n", pin->friendlyName)); +#else + PA_DEBUG(("PinNew: Input friendly name '%S'\n", pin->friendlyName)); +#endif } else // muxCount > 0 { @@ -1777,6 +1822,8 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa for (i = 0; i < muxCount; ++muxPos) { + PA_DEBUG(("PinNew: Setting up input %u...\n", i)); + if (pin->inputs[i] == NULL) { pin->inputs[i] = (PaWinWdmMuxedInput*)PaUtil_AllocateMemory(sizeof(PaWinWdmMuxedInput)); @@ -1814,25 +1861,29 @@ static PaWinWdmPin* PinNew(PaWinWdmFilter* parentFilter, unsigned long pinId, Pa if (result == paNoError) { - result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH); - if (result == paNoError) - { - /* Try pin name also, and if that is defined, use that instead */ - result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, - endpointPinId, - &KSPROPSETID_Pin, - KSPROPERTY_PIN_NAME, - pin->inputs[i]->friendlyName, - MAX_PATH, - NULL); + /* Try pin name first, and if that is not defined, use category instead */ + result = WdmGetPinPropertySimple(pin->parentFilter->topologyFilter->handle, + endpointPinId, + &KSPROPSETID_Pin, + KSPROPERTY_PIN_NAME, + pin->inputs[i]->friendlyName, + MAX_PATH, + NULL); + if (result != paNoError) + { + result = GetNameFromCategory(&category, TRUE, pin->inputs[i]->friendlyName, MAX_PATH); if (result != paNoError) { _snwprintf(pin->inputs[i]->friendlyName, MAX_PATH, L"Input %d", i + 1); } - - ++i; } +#ifdef UNICODE + PA_DEBUG(("PinNew: Input (%u) friendly name '%s'\n", i, pin->inputs[i]->friendlyName)); +#else + PA_DEBUG(("PinNew: Input (%u) friendly name '%S'\n", i, pin->inputs[i]->friendlyName)); +#endif + ++i; } } else @@ -2847,14 +2898,21 @@ static PaWinWdmPin* FilterCreatePin(PaWinWdmFilter* filter, return result == paNoError ? pin : 0; } +static const wchar_t kUsbPrefix[] = L"\\\\?\\USB"; + static BOOL IsUSBDevice(const wchar_t* devicePath) { - return (wcscmp(devicePath, L"\\\\?\\USB") == 0); + /* Alex Lessard pointed out that different devices might present the device path with + lower case letters. */ + return (_wcsnicmp(devicePath, kUsbPrefix, sizeof(kUsbPrefix)/sizeof(kUsbPrefix[0]) ) == 0); } +/* This should make it more language tolerant, I hope... */ +static const wchar_t kUsbNamePrefix[] = L"USB Audio"; + static BOOL IsNameUSBAudioDevice(const wchar_t* friendlyName) { - return (wcscmp(friendlyName, L"USB Audio Device") == 0); + return (_wcsnicmp(friendlyName, kUsbNamePrefix, sizeof(kUsbNamePrefix)/sizeof(kUsbNamePrefix[0])) == 0); } typedef enum _tag_EAlias @@ -3475,7 +3533,7 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH } deviceInfo->defaultHighInputLatency = (4096.0/48000.0); deviceInfo->defaultHighOutputLatency = (4096.0/48000.0); - deviceInfo->defaultSampleRate = (double)(pin->bestSampleRate); + deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate); break; case Type_kWaveRT: /* This is also a conservative estimate, based on WaveRT polled mode. In polled mode, the latency will be dictated @@ -3484,7 +3542,7 @@ static PaError ScanDeviceInfos( struct PaUtilHostApiRepresentation *hostApi, PaH deviceInfo->defaultLowOutputLatency = 0.01; deviceInfo->defaultHighInputLatency = 0.04; deviceInfo->defaultHighOutputLatency = 0.04; - deviceInfo->defaultSampleRate = (double)(pin->bestSampleRate); + deviceInfo->defaultSampleRate = (double)(pin->defaultSampleRate); break; default: assert(0); @@ -5496,8 +5554,8 @@ static PaError PaDoProcessing(PaProcessThreadInfo* pInfo) if (inputFramesAvailable && (!pInfo->stream->userOutputChannels || inputFramesAvailable >= (int)pInfo->stream->render.framesPerBuffer)) { unsigned wrapCntr = 0; - char* data[2] = {0,0}; - ring_buffer_size_t size[2] = {0,0}; + char* data[2] = {0}; + ring_buffer_size_t size[2] = {0}; /* If full-duplex, we just extract output buffer number of frames */ if (pInfo->stream->userOutputChannels) @@ -5527,17 +5585,6 @@ static PaError PaDoProcessing(PaProcessThreadInfo* pInfo) pInfo->stream->deviceInputChannels); } } -#if 0 - if (pInfo->stream->userOutputChannels && pInfo->stream->capture.framesPerBuffer <= pInfo->stream->render.framesPerBuffer) - { - ring_buffer_size_t n = PaUtil_GetRingBufferReadAvailable(&pInfo->stream->ringBuffer); - if (n - inputFramesAvailable > 0) - { - PA_HP_TRACE((pInfo->stream->hLog, "Synchronizing input buffer (read advance = %d) ", n - inputFramesAvailable)); - PaUtil_AdvanceRingBufferReadIndex(&pInfo->stream->ringBuffer, n - inputFramesAvailable); - } - } -#endif } else { @@ -6473,7 +6520,6 @@ static PaError PaPinRenderEventHandler_WaveRTPolled(PaProcessThreadInfo* pInfo, /* And align it, not sure its really needed though */ pos &= ~(pRender->bytesPerFrame - 1); - if (pInfo->priming) { realOutBuf = pInfo->renderHead & 0x1; -- 2.43.0