Skip to content
Snippets Groups Projects
Commit fee498bc authored by Pascal Palenda's avatar Pascal Palenda
Browse files

Merge branch 'release/2023a'

parents c89e9bac 5142a715
No related branches found
No related tags found
No related merge requests found
Showing
with 216 additions and 412 deletions
cmake_minimum_required (VERSION 3.20 FATAL_ERROR)
cmake_minimum_required (VERSION 3.26 FATAL_ERROR)
project (VAPython LANGUAGES CXX C)
project (
VAPython
LANGUAGES CXX C
VERSION 2023.0
)
set (CMAKE_DEBUG_POSTFIX "-d")
......@@ -14,81 +18,29 @@ if (CMAKE_GENERATOR MATCHES "Visual Studio")
set_property (GLOBAL PROPERTY USE_FOLDERS ON)
endif ()
# If build outside of VA project, eg via pip, ...
if (CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
# ... build dependecies static so a single file contains everything needed.
set (BUILD_SHARED_LIBS OFF)
# Additionally, download all dependencies.
set (CPM_DOWNLOAD_VERSION 0.32.2)
set (CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake")
if (NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
message (STATUS "Downloading CPM.cmake")
file (DOWNLOAD https://github.com/TheLartians/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake
${CPM_DOWNLOAD_LOCATION}
)
else (NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
message ("CPM already exists, do not need to download")
endif (NOT (EXISTS ${CPM_DOWNLOAD_LOCATION}))
include (${CPM_DOWNLOAD_LOCATION})
if (NOT TARGET VABase)
CPMAddPackage (
NAME VABase
GIT_REPOSITORY https://git.rwth-aachen.de/ita/VABase
GIT_TAG master
)
endif ()
if (NOT TARGET VANet)
CPMAddPackage (
NAME VANet
GIT_REPOSITORY https://git.rwth-aachen.de/ita/VANet
GIT_TAG master
NAME python-cmake-wheel
GITHUB_REPOSITORY Klebert-Engineering/python-cmake-wheel
GIT_TAG main
DOWNLOAD_ONLY TRUE
)
endif ()
endif ()
if (PYTHON_SETUP_PY_VERSION)
list (APPEND PYTHON_SETUP_PY_VERSION EXACT)
message("${PYTHON_SETUP_PY_VERSION}")
endif ()
list (INSERT CMAKE_MODULE_PATH 0 CMAKE_MODULE_PATH ${python-cmake-wheel_SOURCE_DIR})
find_package (Python ${PYTHON_SETUP_PY_VERSION} REQUIRED COMPONENTS Interpreter Development)
include (python-wheel)
# --- Version ---
# get the version from setup.py
execute_process (
COMMAND ${Python_EXECUTABLE} ${CMAKE_CURRENT_LIST_DIR}/setup.py --version OUTPUT_VARIABLE VAPython_version
)
string (REGEX MATCHALL "([0-9]+)\\.([0-9]+)" _output ${VAPython_version})
unset (_output)
# use the result to set the project version
set (PROJECT_VERSION ${CMAKE_MATCH_0})
set (PROJECT_VERSION_MAJOR ${CMAKE_MATCH_1})
set (PROJECT_VERSION_MINOR ${CMAKE_MATCH_2})
# set the project version in cache for installation and packaging only
if (DEV_HELPERS)
set (
${PROJECT_NAME}_VERSION
${PROJECT_VERSION}
CACHE INTERNAL "Cache entry of the project versions"
)
endif ()
find_package (Python REQUIRED COMPONENTS Interpreter Development.SABIModule)
# Add target 'va', the project name is *not* used here, so in python the module is called 'va'.
python_add_library (
${PROJECT_NAME}
MODULE
USE_SABI
3.8
WITH_SOABI
src/vasingleton.cpp
src/vasingletondoc.hpp
src/vasingletonmethods.hpp
MANIFEST.in
setup.py
)
add_library (VA::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
......@@ -103,30 +55,44 @@ if (NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
set_property (TARGET ${PROJECT_NAME} PROPERTY FOLDER "Bindings/VA")
endif ()
# Remove the debug postfix, so the module always has the same name. Also set the output dir to bin, so if shared build is enabled, the module can find all the dlls.
set_target_properties (${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX "" OUTPUT_NAME "va"
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>/bin")
# Remove the debug postfix, so the module always has the same name. Also set the output dir to bin, so if shared build
# is enabled, the module can find all the dlls.
set_target_properties (
${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX "" LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/$<CONFIG>/bin"
)
# Only run this, if we are not building from setup.py
if (NOT PYTHON_SETUP_PY_BUILD)
set (WHEEL_DEPLOY_DIRECTORY "${CMAKE_BINARY_DIR}/python_wheels")
execute_process (COMMAND py --list OUTPUT_VARIABLE python_versions)
string (REGEX MATCHALL "([0-9]+\\.[0-9]+)" python_versions ${python_versions})
add_wheel (
${PROJECT_NAME}
VERSION
${PROJECT_VERSION}
AUTHOR
"Institute for Hearing Technology and Acoustics (IHTA), RWTH Aachen University"
URL
"https://www.virtualacoustics.org"
LICENSE_PATH
${CMAKE_CURRENT_SOURCE_DIR}/LICENSE.md
PYTHON_REQUIRES
">=3.8"
DESCRIPTION
"Virtual Acoustics (VA) singleton interface"
DEPLOY_FILES
""
TARGET_DEPENDENCIES
VA::VABase # VANet is now static, not needed here.
MODULE_DEPENDENCIES
""
)
add_custom_target (${PROJECT_NAME}_wheel ALL)
file (WRITE ${CMAKE_CURRENT_BINARY_DIR}/setup.cfg "[bdist_wheel]\npy_limited_api = cp38")
foreach (py_version ${python_versions})
add_custom_command (
TARGET ${PROJECT_NAME}_wheel
POST_BUILD
COMMAND py -${py_version} setup.py bdist_wheel
WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}"
COMMENT "Running distutils for version ${py_version}"
VERBATIM
)
endforeach ()
file (READ ${CMAKE_CURRENT_BINARY_DIR}/setup.py setup_CONTENT)
string (REGEX REPLACE "(sources=\\[\\])" "\\1, py_limited_api=True" setup_CONTENT "${setup_CONTENT}") #
file (WRITE ${CMAKE_CURRENT_BINARY_DIR}/setup.py ${setup_CONTENT})
set_property (TARGET ${PROJECT_NAME}_wheel PROPERTY FOLDER "Bindings/VA")
set_property (TARGET ${PROJECT_NAME}-copy-files ${PROJECT_NAME}-setup-py PROPERTY FOLDER "Bindings/VA")
set_property (TARGET wheel PROPERTY FOLDER "Bindings")
# ---Install---
......@@ -144,7 +110,7 @@ if (NOT PYTHON_SETUP_PY_BUILD)
# Wheel files for installation on user machine
install (
DIRECTORY "dist/"
DIRECTORY ${WHEEL_DEPLOY_DIRECTORY}/
DESTINATION ${VA_PYTHON_OUTPUT_FOLDER}
COMPONENT ${PROJECT_NAME}
FILES_MATCHING
......@@ -164,5 +130,3 @@ if (NOT PYTHON_SETUP_PY_BUILD)
DESTINATION ${VA_PYTHON_OUTPUT_FOLDER}
COMPONENT ${PROJECT_NAME}
)
endif ()
Copyright 2015-2022 Institute of Technical Acoustics (ITA), RWTH Aachen University
Copyright 2015-2023 Institute of Technical Acoustics (ITA), RWTH Aachen University
Licensed under the Apache License, Version 2.0 (the "License");
you may not use files of this project except in compliance with the License.
......
......
include README.md LICENSE.md
include src/*.hpp
include src/*.cpp
recursive-include tests *
......@@ -5,7 +5,7 @@ VAPython contains is a C++ extension for the Python3 interpreter that provides a
### License
Copyright 2015-2022 Institute of Technical Acoustics (ITA), RWTH Aachen University
Copyright 2015-2023 Institute of Technical Acoustics (ITA), RWTH Aachen University
Licensed under the Apache License, Version 2.0 (the "License");
you may not use files of this project except in compliance with the License.
......
......
%% Cell type:markdown id: tags:
# VA core controller
This is an example how to control global VA core functionality
%% Cell type:markdown id: tags:
### Prerequisites
%% Cell type:code id: tags:
``` python
import sys
sys.path.append( '../../Lib/site-packages' )
sys.path.append( '../../dist/Lib/site-packages' )
import ipywidgets as widgets
import va
import VAPython as va
if not va.connect() :
raise 'Could not connect to local VA server'
else :
print( 'Successfully connected, server core version is: ' + va.get_version() )
```
%% Output
Successfully connected, server core version is: VACore v2017.d (debug)
%% Cell type:markdown id: tags:
## Control
%% Cell type:markdown id: tags:
### Output
%% Cell type:markdown id: tags:
#### Mute / unmute
You can mute and unmute the entire audio output by using `set_output_muted` and receive the current setting by `is_output_muted`. The setter uses the optional argument `True` or `False` and will mute the output if no argument is passed.
%% Cell type:code id: tags:
``` python
mute_output_button = widgets.ToggleButton( description = 'Output muted', value = va.get_output_muted() )
def on_mute_button_clicked( b ) :
if b.name == 'value' :
va.set_output_muted( b.new ) # True if toggle button appears 'active'
mute_output_button.observe( on_mute_button_clicked )
display( mute_output_button )
```
%% Output
%% Cell type:markdown id: tags:
#### Gain
The output gain or output volume of VA can be controlled by `set_output_gain` and received by `get_output_gain`. Gains or volumes are defined as a factore between 0 and 1. The same functions also exist for the audio inputs of the sound device.
%% Cell type:code id: tags:
``` python
output_gain_slider = widgets.FloatSlider(
value = va.get_output_gain(),
description = 'Output gain:',
min = 0.0,
max = 1.0,
step = 0.1,
readout = True,
readout_format = '.1f' )
def on_output_gain_changed( s ) :
if s.name == 'value' :
va.set_output_gain( s.new )
output_gain_slider.observe( on_output_gain_changed )
display( output_gain_slider )
```
%% Output
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
<ipython-input-1-d87da51b8000> in <module>()
----> 1 output_gain_slider = widgets.FloatSlider(
2 value = va.get_output_gain(),
3 description = 'Output gain:',
4 min = 0.0,
5 max = 1.0,
NameError: name 'widgets' is not defined
%% Cell type:markdown id: tags:
#### Global auralization mode
The auralization mode is a bundle of flags to control the acoustic phenomena that should be considered during audio rendering. It's purpose is to demonstrate the audibility of certain aspects, like sound source directivity.
Auralization mode can be set globally, but also individually for rendering modules, sources and receivers.
%% Cell type:code id: tags:
``` python
global_am = va.get_global_auralization_mode()
print( global_am )
global_am_long = va.get_global_auralization_mode( False )
print( global_am_long )
```
%% Output
DS, ER, DD, DIR, AA, TV, SC, DIF, NF, DP, SL, TR, AB
Direct sound, early reflections, diffuse decay, source directivity, air absorption, atmospheric temporal variations, scattering, diffraction, near-field effects, doppler shifts, spherical spreading loss, transmission, absorption
%% Cell type:markdown id: tags:
### Macros
Macros can be defined to make your life easier. Don't mess around with file pathes too much, use macros. Don't rename output file names for recording and other exported information, use macros. You can test your macros using th method `substitute_macro` (see below), but you don't have to do it yourself. VA will always substitute macros where possible.
%% Cell type:code id: tags:
``` python
print( '$(DefaultHRIR): ' + va.substitute_macro( '$(DefaultHRIR)' ) )
print( '$(ProjectName): ' + va.substitute_macro( '$(ProjectName)' ) )
print( '$(data): ' + va.substitute_macro( '$(data)' ) )
print( '$(big_data_dir): ' + va.substitute_macro( '$(big_data_dir)' ) )
print( '$(conf): ' + va.substitute_macro( '$(conf)' ) )
```
%% Output
$(DefaultHRIR): HRIR\\ITA-Kunstkopf_HRIR_AP11_Pressure_Equalized_3x3_256.v17.ir.daff
$(ProjectName): MyVirtualAcousticsProject
$(data): $(data)
$(big_data_dir): C:\\data
$(conf): $(conf)
%% Cell type:markdown id: tags:
### Paths
Using search path is encouraged, as it makes it easier to move from one PC to another. You can get the available search paths and also add new search paths. Paths are always bound to the server PC.
%% Cell type:code id: tags:
``` python
print( va.get_search_paths() )
import os
current_working_dir = os.getcwd()
print( "client working directory: " + current_working_dir )
va.add_search_path( current_working_dir ); # only makes sense if client and server are running on same PC
```
%% Output
{'path_0': 'C:/data', 'path_1': 'C:/dev/VA/VACore/conf', 'path_2': 'C:/dev/VA/VACore/data', 'path_3': 'C:/data/InsideSceneData'}
client working directory: C:\dev\VA\VAPython\examples\jupyter
%% Cell type:markdown id: tags:
### Reset
Use `reset` to reset the entire scene.
%% Cell type:code id: tags:
``` python
reset_button = widgets.Button( description = 'Reset VA server' )
def on_reset_button_clicked( b ) :
va.reset()
reset_button.on_click( on_reset_button_clicked )
display( reset_button )
```
%% Output
%% Cell type:markdown id: tags:
## Modules
You can interact with any registered VA module using a magic struct. In Python, this struct is represented by a (nested) dictionary, that is translated to a VAStruct. This struct can be used to call modules and receive information in return. It is used to change any setting in a registered module. This way, no new interface methods for prototyping have to be added during development and testing.
%% Cell type:code id: tags:
``` python
allmods = va.get_modules()
modnames = list()
for mod in allmods[:] :
modnames.append( mod["name"] )
mods_dropdown_menu = widgets.Dropdown( options=modnames )
mod_call_button = widgets.Button( description = 'Call' )
mod_widget_box = widgets.HBox( [ mods_dropdown_menu, mod_call_button ] )
def on_mod_call( b ) :
mod = allmods[ mods_dropdown_menu.index ]
print( 'Calling ' + mod["name"] )
modnames.append( mod["name"] )
try :
va.call_module( mod["name"], { 'help': True } )
except :
print( 'Module returned an exception, could not get help' )
mod_call_button.on_click( on_mod_call )
display( mod_widget_box )
```
%% Output
Calling BinauralFreeField:MyBinauralFreeField
Module returned an exception, could not get help
Calling VACore
%% Cell type:markdown id: tags:
### Rendering modules
Rendering modules are special modules that can also be listed using `get_rendering_modules`. They can be muted/unmuted individually and also have an own output gain control. Additionally all rendering modules have specialized parameter setter and getter.
%% Cell type:code id: tags:
``` python
allrendmods = va.get_rendering_modules();
# Dropdown menu
rendmodnames = list()
for mod in allrendmods[:] :
rendmodnames.append( mod["id"] )
rendmods_dropdown_menu = widgets.Dropdown( options=rendmodnames )
# Mute toggle button
rendmod_mute_button = widgets.ToggleButton( description = 'Mute' )
def on_rendmod_mute_button_clicked( b ) :
rendmod = allrendmods[ rendmods_dropdown_menu.index ]
if b.name == 'value' :
va.set_rendering_module_muted( mod["id"], b.new )
rendmod_mute_button.observe( on_rendmod_mute_button_clicked )
# Gain slider
rendmod_gain_slider = widgets.FloatSlider(
value = 1.0,
description = 'Gain:',
min = 0.0,
max = 1.0,
step = 0.1,
readout = True,
readout_format = '.1f' )
def on_rendmod_gain_changed( s ) :
rendmod = allrendmods[ rendmods_dropdown_menu.index ]
if s.name == 'value' :
va.set_rendering_module_gain( rendmod["id"], s.new )
rendmod_gain_slider.observe( on_rendmod_gain_changed )
# Parameter getter
rendmod_button_params = widgets.Button( description = 'Parameters' )
def on_rendmod_parameter( b ) :
rendmod = allrendmods[ rendmods_dropdown_menu.index ]
print( va.get_rendering_module_parameters( rendmod["id"] ) )
rendmod_button_params.on_click( on_rendmod_parameter )
# Horizontal box with widgets
rendmod_widget_box = widgets.HBox( [ rendmods_dropdown_menu, rendmod_mute_button, rendmod_gain_slider, rendmod_button_params ] )
display( rendmod_widget_box )
```
%% Output
%% Cell type:markdown id: tags:
### Reproduction modules
Reproduction modules are special modules that can also be listed using `get_reproduction_modules`. They can be muted/unmuted individually and also have an own output gain control. Additionally all reproduction modules have specialized parameter setter and getter.
%% Cell type:code id: tags:
``` python
allrepmods = va.get_reproduction_modules();
# Dropdown menu
repmodnames = list()
for mod in allrepmods[:] :
repmodnames.append( mod["id"] )
repmods_dropdown_menu = widgets.Dropdown( options=repmodnames )
# Mute toggle button
repmod_mute_button = widgets.ToggleButton( description = 'Mute' )
def on_repmod_mute_button_clicked( b ) :
repmod = allrepmods[ repmods_dropdown_menu.index ]
if b.name == 'value' :
va.set_reproduction_module_muted( mod["id"], b.new )
repmod_mute_button.observe( on_repmod_mute_button_clicked )
# Gain slider
repmod_gain_slider = widgets.FloatSlider(
value = 1.0,
description = 'Gain:',
min = 0.0,
max = 1.0,
step = 0.1,
readout = True,
readout_format = '.1f' )
def on_repmod_gain_changed( s ) :
repmod = allrepmods[ repmods_dropdown_menu.index ]
if s.name == 'value' :
va.set_reproduction_module_gain( repmod["id"], s.new )
repmod_gain_slider.observe( on_repmod_gain_changed )
# Parameter getter
repmod_button_params = widgets.Button( description = 'Parameters' )
def on_repmod_parameter( b ) :
repmod = allrepmods[ repmods_dropdown_menu.index ]
print( va.get_reproduction_module_parameters( repmod["id"] ) )
repmod_button_params.on_click( on_repmod_parameter )
# Horizontal box with widgets
repmod_widget_box = widgets.HBox( [ repmods_dropdown_menu, repmod_mute_button, repmod_gain_slider, repmod_button_params ] )
display( repmod_widget_box )
```
%% Output
{}
......
......
%% Cell type:markdown id: tags:
# VA experimental renderer example
VA has prototype renderers, that can be used for quick auralization of any given situation. A renderer of the **PrototypeGenericPath** class uses a uniform block convolution of required number of channels and filter length. For each source-listener-pair, a new convolution instance is provided. It can be updated using the parameter setter, i.e. the FIR filter can be updated in real-time with an impulse resonse (IR) in time domain directly out of Python (or Matlab). On server side, no files (except for the signal sources, if an audio file is used) have to be provided.
The filter length, the number of channels and the number of source-listener-pairs are only limited by the computational power you can provide.
This combination of a VA server with an experimental rendering module using the **PrototypeGenericPath** renderer can effectively be used for teaching purposes, i.e. to implement a real-time binaural auralization in Python or Matlab.
%% Cell type:markdown id: tags:
### Prerequisites
%% Cell type:code id: tags:
``` python
import sys
#sys.path.append( '../../Lib/site-packages' )
sys.path.append( '../../dist/Lib/site-packages' )
import ipywidgets as widgets
import va
import VAPython as va
if not va.connect() :
raise 'Could not connect to local VA server'
else :
print( 'Successfully connected, server core version is: ' + va.get_version() )
```
%% Output
Successfully connected, server core version is: VACore v2017.d (debug)
%% Cell type:markdown id: tags:
## Auralize room acoustics with a measured binaural room impulse response (BRIR)
### Configuration
You have to start a VA server, that instatiates a **PrototypeGenericPath** renderer with **two channels** and a filter length that is long enough to fit the reverberation time of the room you want to make audible, for example **2 seconds** (or **88200 samples** at a sampling frequency of 44.1 kHz). If you start the experimental server provided with a VA binary package, this configuration is already in place. See also `conf/VACore.experimental.ini` for further details.
### Rendering module name
Check out the rendering module name to know which rendering module to call. Use `get_rendering_modules` like this:
%% Cell type:code id: tags:
``` python
for rmod in va.get_rendering_modules() :
if rmod['class'] == 'PrototypeGenericPath' :
print( rmod['id'] )
rmod_name = 'Experimental' # alter this if you are using a different name
```
%% Output
Experimental
%% Cell type:markdown id: tags:
### Get renderer information
To receive useful information, renderer usually return available configurations if `get_renderer_parameters` is called without arguments. Try this:
%% Cell type:code id: tags:
``` python
rmod_generic_info = va.get_rendering_module_parameters( rmod_name )
from IPython.display import Markdown, display
display( Markdown( rmod_generic_info[ 'help' ] ) )
```
%% Output
--- GenericPath renderer instance 'Experimental' ---
[help]
If the call module struct contains a key with the name 'help', this help text will be shown and the return struct will be returned with the key name 'help'.
[info]
If the call module struct contains a key with the name 'info', information on the static configuration of the renderer will be returned.
[update]
For every successful path update, the VA source and sound receiver ID has to be passed like this:
receiver: <int>, the number of the sound receiver identifier
source: <int>, the number of the source identifier
Updating the path filter (impulse response in time domain) for a sound receiver and a source can be performed in two ways:
a) using a path to a multi-channel WAV file:
Provide a key with the name 'filepath' and the path to the WAV file (absolute or containing the macro '$(VADataDir)' or relative to the executable) [priority given to 'filepath' if b) also applies]
b) sending floating-point data for each channel
Provide a key for each channel with the generic name 'ch#', where the hash is substituted by the actual number of channel (starting at 1), and the value to this key will contain floating point data (or a sample buffer). The call parameter struct does not necessarily have to contain all channels, also single channels will be updated if key is given.
Note: the existence of the key 'verbose' will print update information at server console and will provide the update info as an 'info' key in the returned struct.
%% Cell type:markdown id: tags:
Or, now that we know we should use the `info` key, type
%% Cell type:code id: tags:
``` python
va.get_rendering_module_parameters( rmod_name, { 'info' : True } )
```
%% Output
{'filterdelaysamples': 0,
'irfilterlengthsamples': 88200,
'numchannels': 2,
'numpaths': 0}
%% Cell type:markdown id: tags:
### Input data preparation
Let us quickly set up a virtual scene using input data from the Internet.
Download for example anechoic recordings directly from [here](http://www.openairlib.net/sites/default/files/anechoic/data/judebrereton/modern-clarinet-bb/mono/cl-mod-bb-piece-32.wav) and a binaural impulse response from [here](http://www.openairlib.net/sites/default/files/auralization/data/audiolab/lady-chapel-st-albans-cathedral/stereo/stalbans_a_binaural.wav). Either add the download folder as search path, or put the files where VA can find it (e.g. in the `data` folder).
%% Cell type:code id: tags:
``` python
va.add_search_path( '../../../VACore/data' )
va.add_search_path( 'C:\dev\VA\VACore\data' )
signal_source_id = va.create_signal_source_buffer_from_file( 'cl-mod-bb-piece-32.wav' )
va.set_signal_source_buffer_playback_action_str( signal_source_id, 'play' )
va.set_signal_source_buffer_looping( signal_source_id, True )
```
%% Cell type:markdown id: tags:
### Creating the scene
To update a source-listener-pair, a scene should be set up.
%% Cell type:code id: tags:
``` python
sound_source_id = va.create_sound_source( 'PyExperimentalSoundSource' )
print( 'Experimental sound source id: ' + str( sound_source_id ) )
va.set_sound_source_signal_source( sound_source_id, signal_source_id )
receiver_id = va.create_sound_receiver( 'PyExperimentalListener' )
print( 'Experimental listener id: ' + str( sound_source_id ) )
```
%% Output
Experimental sound source id: 1
Experimental listener id: 1
%% Cell type:markdown id: tags:
### Updating paths
Now that we have a source-listener-pair established, we can update the impulse response of that path. To do so, we have to assembly a `dict` variable that provides the required information. This `dict` will be transmitted to the renderer and the update will be performed.
### Setting a simple unequal two-channel dirac
%% Cell type:code id: tags:
``` python
update_dirac = dict()
update_dirac[ 'receiver' ] = receiver_id
update_dirac[ 'source' ] = sound_source_id
update_dirac[ 'ch1' ] = [ 0.9, 0.0, 0.0, 0.0 ] # Length of samples is arbitrary, here
update_dirac[ 'ch2' ] = [ 0.0, 0.0, -0.4, 0.0 ] # Length of samples is arbitrary, here
update_dirac[ 'verbose' ] = True; # Get information about update as a result
print( update_dirac )
```
%% Output
{'receiver': 1, 'source': 1, 'ch1': [0.9, 0.0, 0.0, 0.0], 'ch2': [0.0, 0.0, -0.4, 0.0], 'verbose': True}
%% Cell type:markdown id: tags:
Now all we have to do is transmit the update task to the renderer
%% Cell type:code id: tags:
``` python
va.set_rendering_module_parameters( rmod_name, update_dirac )
```
%% Cell type:markdown id: tags:
### Update by loading from a file path
It is not necessary to transmit an entire impulse response for each channel to the path you want to update. You can also use a file path for a single or all channels.
%% Cell type:code id: tags:
``` python
update_filepath = dict()
update_filepath[ 'receiver' ] = receiver_id
update_filepath[ 'source' ] = sound_source_id
update_filepath[ 'filepath' ] = 'stalbans_a_binaural.wav'
#update_filepath[ 'channel' ] = 2 # ... in case you explicitly want to update a single channel with a mono IR file
update_filepath[ 'verbose' ] = True;
print( update_filepath )
```
%% Output
{'receiver': 1, 'source': 1, 'filepath': 'stalbans_a_binaural.wav', 'verbose': True}
%% Cell type:code id: tags:
``` python
va.set_rendering_module_parameters( rmod_name, update_filepath )
```
%% Cell type:markdown id: tags:
### Update by loading samples into Python and transmit IR
If you want to load an manipulate samples using Python, you can do the following. Make sure that the file is in the same folder of this notebook, or modify path accordingly.
You can use `scipy` or `wave` to obtain data from a WAVE file, however sample type conversion might be an issue because they usually only provide integer type, and VA requires floating point samples. In this example, the input file is a 24bit signed integer.
%% Cell type:code id: tags:
``` python
import wave, struct
w = wave.open( 'stalbans_a_binaural.wav' )
raw_ir = w.readframes( w.getnframes() )
ir_length = w.getnframes()
ir_channels = w.getnchannels()
assert( w.getsampwidth() == 3 )
# Deinterleave and convert sample type (slow implementation, but more easy to interpret)
ir = list()
for n in range( ir_channels ) :
ir.append( [] )
for i in range( ir_length ) :
rbegin = 3 * ( n + i * ir_channels + 0 )
rend = 3 * ( n + i * ir_channels + 1 )
sample_sint24 = raw_ir[ rbegin : rend ]
sample_sint32 = sample_sint24 + ( b'\0' if sample_sint24[2] < 128 else b'\xff' )
sample_float = ( struct.unpack( 'i', sample_sint32 )[0] ) / pow( 2, 24 - 1 )
ir[ n ].append( sample_float )
print( 'Loaded an impulse response of %i channel(s) with %i filter taps.' % ( len( ir ), len( ir[ 0 ] ) ) )
```
%% Output
Loaded an impulse response of 2 channel(s) with 264600 filter taps.
%% Cell type:code id: tags:
``` python
update_ir = dict()
update_ir[ 'receiver' ] = receiver_id
update_ir[ 'source' ] = sound_source_id
update_ir[ 'ch1' ] = ir[ 0 ]; # Requires ir samples to be floating point, so sample type conversion might be required
update_ir[ 'ch2' ] = ir[ 1 ]; # Requires ir samples to be floating point, so sample type conversion might be required
update_ir[ 'verbose' ] = True;
```
%% Cell type:code id: tags:
``` python
va.set_rendering_module_parameters( rmod_name, update_ir )
```
......
......
%% Cell type:markdown id: tags:
# VA notebook test
This is a simple test program that demonstrates the use of the VA Python binding within a jupyter notebook environment.
## Before we start
Before we start scripting, let's make VA available for us. If it is not installed and available from everywhere, this is how you can add the `va` module folder:
%% Cell type:code id: tags:
``` python
import sys
sys.path.append( "../../dist/Lib/site-packages" ) # build
sys.path.append( "../Lib/site-packages" ) # deploy
```
%% Cell type:markdown id: tags:
## Start
We start by making va available for our script
%% Cell type:code id: tags:
``` python
import va
import VAPython as va
```
%% Cell type:markdown id: tags:
Ok. Now let's try to connect to the VA server that should be running on the same computer where this jupyter notebook is running.
%% Cell type:markdown id: tags:
We start by finding out where we are currently working and list the files available, i.e. to identify files that can be used as HRIR, audio file or directivity.
%% Cell type:code id: tags:
``` python
connection_status = va.connect()
```
%% Cell type:markdown id: tags:
We can check the connection by the following line
%% Cell type:code id: tags:
``` python
connected = va.is_connected()
if connected :
print( "VA connection ready!" )
else :
print( "Something went wrong." )
```
%% Cell type:markdown id: tags:
... and also use different server names and ports
%% Cell type:code id: tags:
``` python
if not connected :
va.connect( "localhost", 12340 ) # these are the default arguments
```
%% Cell type:code id: tags:
``` python
import os
current_working_dir = os.getcwd()
print( "working directory: " + current_working_dir )
```
%% Cell type:markdown id: tags:
Now lets add this folder to VA. This means that VA can find files that reside in this location. All you have to do is use a file name or a relative path from this base path. You can add as much folders as you like.
%% Cell type:code id: tags:
``` python
va.add_search_path( current_working_dir )
```
%% Cell type:code id: tags:
``` python
vamods = va.get_modules()
print( vamods )
```
%% Cell type:code id: tags:
``` python
hw = va.get_hardware_configuration()
print( hw )
```
%% Cell type:code id: tags:
``` python
core_conf = va.get_core_configuration()
print( core_conf )
```
......
......
%% Cell type:markdown id: tags:
# VA scene controller
This is a simple example and utility notebook that demonstrates the use of scene control mechanisms.
%% Cell type:markdown id: tags:
### Prerequisites
You can ignore this part, it is for preparation purposes only.
%% Cell type:code id: tags:
``` python
import sys
sys.path.append( '../../Lib/site-packages' )
sys.path.append( '../../dist/Lib/site-packages' )
import ipywidgets as widgets
import va
import VAPython as va
if not va.connect() :
raise 'Could not connect to VA server on localhost'
```
%% Cell type:markdown id: tags:
### Sound receiver
%% Cell type:code id: tags:
``` python
sound_receiver_ids = va.get_sound_receiver_ids()
sound_receivers_dict = {}
for sound_receiver_id in sound_receiver_ids :
sound_receivers_dict.update( { va.get_sound_receiver_name( sound_receiver_id ) : sound_receiver_id } )
sound_receivers_dropdown_menu = widgets.Dropdown(
options = sound_receivers_dict,
description = 'Sound receivers' )
if sound_receiver_ids :
first_sound_receiver_pos = va.get_sound_receiver_position( sound_receiver_ids[ 0 ] )
def on_sound_receiver_update( w ) :
sound_receiver_id = sound_receivers_dropdown_menu.value
if sound_receiver_id :
sound_receiver_pos = [ sound_receivers_input_pos_x.value, sound_receivers_input_pos_y.value, sound_receivers_input_pos_z.value ]
va.set_sound_receiver_position( sound_receiver_id, sound_receiver_pos )
sound_receivers_input_pos_x = widgets.FloatText( description = 'X' )
sound_receivers_input_pos_y = widgets.FloatText( description = 'Y' )
sound_receivers_input_pos_z = widgets.FloatText( description = 'Z' )
sound_receiver_update_button = widgets.Button( description = 'Update' )
sound_receiver_update_button.on_click( on_sound_receiver_update )
def on_sound_receiver_select( d ) :
if d.type == 'change' and type( d.new ) is str :
sound_receiver_id = sound_receivers_dropdown_menu.options[ d.new ]
sound_receiver_pos = va.get_sound_receiver_position( sound_receiver_id )
sound_receivers_input_pos_x.value = sound_receiver_pos[ 0 ]
sound_receivers_input_pos_y.value = sound_receiver_pos[ 1 ]
sound_receivers_input_pos_z.value = sound_receiver_pos[ 2 ]
sound_receivers_dropdown_menu.observe( on_sound_receiver_select )
sound_receivers_input_widget_box = widgets.HBox( [ sound_receivers_dropdown_menu, sound_receivers_input_pos_x, sound_receivers_input_pos_y, sound_receivers_input_pos_z, sound_receiver_update_button ] )
display( sound_receivers_input_widget_box )
```
%% Output
---------------------------------------------------------------------------
Exception Traceback (most recent call last)
<ipython-input-2-28e67d0dde0f> in <module>()
8 description = 'Sound receivers' )
9 if sound_receiver_ids :
---> 10 first_sound_receiver_pos = va.get_sound_receiver_position( sound_receiver_ids[ 0 ] )
11
12 def on_sound_receiver_update( w ) :
Exception: Not implemented (error code 8)
%% Cell type:markdown id: tags:
### Sources
%% Cell type:code id: tags:
``` python
sound_source_ids = va.get_sound_source_ids()
sound_sources_dict = {}
for source_id in sound_source_ids :
sound_sources_dict.update( { va.get_sound_source_name( source_id ) : source_id } )
sound_sources_dropdown_menu = widgets.Dropdown(
options = sound_sources_dict,
description = 'Sound sources' )
if sound_source_ids :
first_sound_source_pos = va.get_sound_source_position( sound_source_ids[ 0 ] )
def on_sound_source_update( w ) :
sound_source_id = sound_sources_dropdown_menu.value
if sound_source_id :
sound_source_pos = [ sound_source_input_pos_x.value, sound_source_input_pos_y.value, sound_source_input_pos_z.value ]
va.set_sound_source_position( sound_source_id, sound_source_pos )
sound_source_input_pos_x = widgets.FloatText( description = 'X' )
sound_source_input_pos_y = widgets.FloatText( description = 'Y' )
sound_source_input_pos_z = widgets.FloatText( description = 'Z' )
sound_source_update_button = widgets.Button( description = 'Update' )
sound_source_update_button.on_click( on_sound_source_update )
def on_sound_source_select( d ) :
if d.type == 'change' and type( d.new ) is str :
sound_source_id = sound_sources_dropdown_menu.options[ d.new ]
sound_source_pos = va.get_sound_source_position( sound_source_id )
sound_source_input_pos_x.value = sound_source_pos[ 0 ]
sound_source_input_pos_y.value = sound_source_pos[ 1 ]
sound_source_input_pos_z.value = sound_source_pos[ 2 ]
sound_sources_dropdown_menu.observe( on_sound_source_select )
sound_source_input_widget_box = widgets.HBox( [ sound_sources_dropdown_menu, sound_source_input_pos_x, sound_source_input_pos_y, sound_source_input_pos_z, sound_source_update_button ] )
display( sound_source_input_widget_box )
```
%% Output
......
......
%% Cell type:markdown id: tags:
# VA core controller
This is a simple example how to manage signal source.
> This script is intended to be used during a VA session with a scene already set up.
%% Cell type:markdown id: tags:
### Prerequisites
%% Cell type:code id: tags:
``` python
import sys
sys.path.append( '../../Lib/site-packages' )
import ipywidgets as widgets
import va
import VAPython as va
if not va.connect() :
raise Exception( 'Could not connect to local VA server' )
```
%% Output
c:\users\jonas\appdata\local\programs\python\python36\lib\site-packages\ipykernel_launcher.py:5: RuntimeWarning: Was still connected, forced disconnect.
"""
%% Cell type:markdown id: tags:
## Signal sources
In VA, signal sources represent the emitted sound that is released from a virtual sound source. There are a few different types available, and most of them can be created and controlled dynamically.
%% Cell type:markdown id: tags:
### List available signal sources
%% Cell type:code id: tags:
``` python
signal_sources = va.get_signal_source_infos()
if not signal_sources :
raise Exception( 'There are no signal sources available, stopping here.' )
signal_sources_type = list()
for signal_source in signal_sources :
signal_sources_type.append( signal_source['type'] )
children = [ widgets.Text( description = name ) for name in signal_sources_type ]
tab = widgets.Tab()
tab.children = children
for i in range( len( children ) ):
tab.set_title( i, signal_sources_type[ i ] )
display( tab )
```
%% Output
......
......
%% Cell type:markdown id: tags:
# VA simple acoustic scene
This is an example notebook how to create a simple acoustic scene in VA using Python.
%% Cell type:markdown id: tags:
#### Prerequisites
If VA Python extension is not installed, add the folder manually.
%% Cell type:code id: tags:
``` python
import sys
sys.path.append( '../../Lib/site-packages' ) # deploy
sys.path.append( '../../dist/Lib/site-packages' ) # dev
import os
print( 'Current working directory:', os.getcwd() )
import va
import VAPython as va
print( 'Successfully loaded VA Python extension')
```
%% Cell type:markdown id: tags:
### Connect
%% Cell type:code id: tags:
``` python
if not va.connect( 'localhost' ) :
raise 'Could not connect to server on localhost, not running?'
```
%% Cell type:markdown id: tags:
Reset VA to clear the scene
%% Cell type:code id: tags:
``` python
va.reset()
```
%% Cell type:markdown id: tags:
Control output gain
%% Cell type:code id: tags:
``` python
va.set_output_gain( 0.25 )
```
%% Cell type:markdown id: tags:
Add the current working directory and any further relative or absolute directories where you want to put resource files. VA provides search paths where to look for any file. From now on, only use relative paths or macros to paths.
> Pathes are relevant on server side, not on a remote client. The files must be available on the computer **where the VA application is running**!
%% Cell type:code id: tags:
``` python
va.add_search_path( os.getcwd() );
va.add_search_path( 'C:\dev\VA\VACore\data' );
```
%% Cell type:markdown id: tags:
### Signal source
Create a signal source from a file and start playback with looping mode
%% Cell type:code id: tags:
``` python
signal_source_id = va.create_signal_source_buffer_from_file( '$(DemoSound)' )
va.set_signal_source_buffer_playback_action_str( signal_source_id, 'play' )
va.set_signal_source_buffer_looping( signal_source_id, True )
```
%% Cell type:markdown id: tags:
### Virtual sound source
Create a virtual sound source with any name and set a position
%% Cell type:code id: tags:
``` python
sound_source_id = va.create_sound_source( 'PySoundSource' )
va.set_sound_source_position( sound_source_id, ( 1.5, 1.7, -1.1 ) )
```
%% Cell type:markdown id: tags:
### Connect signal and source
Connect the signal source to the virtual sound source
%% Cell type:code id: tags:
``` python
va.set_sound_source_signal_source( sound_source_id, signal_source_id )
```
%% Cell type:markdown id: tags:
### Head-related transfer function / Head-related impulse response
Load an HRIR (time domain representation of an HRTF) as a directivity that will be assigned to a sound receiver (aka listener). See [OpenDAFF](http://www.opendaff.org) for more information.
> We use a macro `DefaultHRIR` here, that is usually available for a VA core.
%% Cell type:code id: tags:
``` python
hrir_id = va.create_directivity_from_file( '$(DefaultHRIR)' )
```
%% Cell type:markdown id: tags:
### Virtual listener
Create a sound receiver with arbitrary name, assign the HRTF/HRIR and set a position.
%% Cell type:code id: tags:
``` python
listener_id = va.create_sound_receiver( 'PyListener' )
va.set_sound_receiver_position( listener_id, ( 0, 1.7, 0 ) )
va.set_sound_receiver_orientation_vu( listener_id, ( 0, 0, -1, ), ( 0, 1, 0 ) ) # Default view is to -Z (OpenGL)
va.set_sound_receiver_directivity( listener_id, hrir_id )
```
%% Cell type:markdown id: tags:
### Active listener
Set an active listener. This concept is deprecated, but should be used for compatibility until it is removed.
%% Cell type:code id: tags:
``` python
va.set_active_sound_receiver( listener_id )
```
%% Cell type:markdown id: tags:
### Disconnect
%% Cell type:code id: tags:
``` python
va.disconnect();
```
......
......
......@@ -2,7 +2,7 @@ import os
current_exec_dir = os.getcwd()
# Make sure you installed the va module
import va
import VAPython as va
va.connect() # localhost
va.reset()
......
......
import os
import re
import subprocess
import sys
import shutil
from pathlib import Path
from warnings import warn
from setuptools import Extension, setup
from setuptools.command.build_ext import build_ext
# Convert distutils Windows platform specifiers to CMake -A arguments
PLAT_TO_CMAKE = {
"win32": "Win32",
"win-amd64": "x64",
"win-arm32": "ARM",
"win-arm64": "ARM64",
}
# A CMakeExtension needs a sourcedir instead of a file list.
# The name must be the _single_ output extension from the CMake build.
# If you need multiple extensions, see scikit-build.
class CMakeExtension(Extension):
def __init__(self, name, sourcedir=""):
Extension.__init__(self, name, sources=[])
self.sourcedir = os.path.abspath(sourcedir)
class CMakeBuild(build_ext):
def build_extension(self, ext):
# check for CMake in Path, if not and on windows try to find it in programs directory
if shutil.which('cmake') == None and sys.platform == 'win32':
possibleExes = list(Path('C:/').glob('*/*cmake*/bin/cmake.exe'))
if not possibleExes and possibleExes[0].is_file:
os.environ['PATH'] += ';' + str(possibleExes[0].absolute())
warn('Did not find CMake in PATH, adding it manually for this script')
# check again for CMake in Path
if shutil.which('cmake') == None:
raise RuntimeError('CMake not found in PATH')
extdir = os.path.abspath(os.path.dirname(self.get_ext_fullpath(ext.name)))
# required for auto-detection & inclusion of auxiliary "native" libs
if not extdir.endswith(os.path.sep):
extdir += os.path.sep
debug = int(os.environ.get("DEBUG", 0)) if self.debug is None else self.debug
cfg = "Debug" if debug else "Release"
# CMake lets you override the generator - we need to check this.
# Can be set with Conda-Build, for example.
cmake_generator = os.environ.get("CMAKE_GENERATOR", "")
# Set Python_EXECUTABLE instead if you use PYBIND11_FINDPYTHON
# EXAMPLE_VERSION_INFO shows you how to pass a value into the C++ code
# from Python.
cmake_args = [
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY={extdir}",
f"-DPYTHON_EXECUTABLE={sys.executable}",
f"-DCMAKE_BUILD_TYPE={cfg}", # not used on MSVC, but no harm
]
build_args = []
# Adding CMake arguments set as environment variable
# (needed e.g. to build for ARM OSx on conda-forge)
if "CMAKE_ARGS" in os.environ:
cmake_args += [item for item in os.environ["CMAKE_ARGS"].split(" ") if item]
if self.compiler.compiler_type != "msvc":
# Using Ninja-build since it a) is available as a wheel and b)
# multithreads automatically. MSVC would require all variables be
# exported for Ninja to pick it up, which is a little tricky to do.
# Users can override the generator with CMAKE_GENERATOR in CMake
# 3.15+.
if not cmake_generator:
try:
import ninja # noqa: F401
cmake_args += ["-GNinja"]
except ImportError:
pass
else:
# Single config generators are handled "normally"
single_config = any(x in cmake_generator for x in {"NMake", "Ninja"})
# CMake allows an arch-in-generator style for backward compatibility
contains_arch = any(x in cmake_generator for x in {"ARM", "Win64"})
# Specify the arch if using MSVC generator, but only if it doesn't
# contain a backward-compatibility arch spec already in the
# generator name.
if not single_config and not contains_arch:
cmake_args += ["-A", PLAT_TO_CMAKE[self.plat_name]]
# Multi-config generators have a different way to specify configs
if not single_config:
cmake_args += [
f"-DCMAKE_LIBRARY_OUTPUT_DIRECTORY_{cfg.upper()}={extdir}"
]
build_args += ["--config", cfg]
if sys.platform.startswith("darwin"):
# Cross-compile support for macOS - respect ARCHFLAGS if set
archs = re.findall(r"-arch (\S+)", os.environ.get("ARCHFLAGS", ""))
if archs:
cmake_args += ["-DCMAKE_OSX_ARCHITECTURES={}".format(";".join(archs))]
# Set CMAKE_BUILD_PARALLEL_LEVEL to control the parallel build level
# across all generators.
if "CMAKE_BUILD_PARALLEL_LEVEL" not in os.environ:
# self.parallel is a Python 3 only way to set parallel jobs by hand
# using -j in the build_ext call, not supported by pip or PyPA-build.
if hasattr(self, "parallel") and self.parallel:
# CMake 3.12+ only.
build_args += [f"-j{self.parallel}"]
if not os.path.exists(self.build_temp):
os.makedirs(self.build_temp)
# cmake_args += ["-DPYTHON_SETUP_PY_BUILD=ON"]
cmake_args += ["-DPYTHON_SETUP_PY_BUILD=ON", "-DPYTHON_SETUP_PY_VERSION={}.{}".format(sys.version_info[0],sys.version_info[1])]
subprocess.check_call(
["cmake", ext.sourcedir] + cmake_args, cwd=self.build_temp
)
subprocess.check_call(
["cmake", "--build", "."] + build_args, cwd=self.build_temp
)
setup(
name="va",
description = 'Virtual Acoustics (VA) singleton interface',
version="2022.0",
author="Institute for Hearing Technology and Acoustics (IHTA), RWTH Aachen University",
author_email="post@akustik.rwth-aachen.de",
url = 'https://www.virtualacoustics.org',
long_description = '''
Virtual Acoustics (VA) is a real-time auralization framework for Virtual Reality. This module is an interface to interact with a VA server.
''',
license = "Copyright 2017-2021. Apache License Version 2.0",
ext_modules=[CMakeExtension("va")],
cmdclass={"build_ext": CMakeBuild},
python_requires=">=3.7",
)
#ifndef IW_VA_PYTHON_COMMON
#define IW_VA_PYTHON_COMMON
// Temporarily "disable" debug to include Python.
// This is done, so that the Python debug libraries are not needed, even when building
// this module in debug mode.
#ifdef _DEBUG
# define TMP_DEBUG
# undef _DEBUG
// Fix msvc compiler issue error C2039: '_invalid_parameter': is not a member of '`global namespace''
// See https://github.com/microsoft/STL/issues/2335#issuecomment-967293809 for more detail
# define _STL_CRT_SECURE_INVALID_PARAMETER( expr ) _CRT_SECURE_INVALID_PARAMETER( expr )
#endif
#include <Python.h>
#ifdef TMP_DEBUG
# define _DEBUG
# undef TMP_DEBUG
#endif
#endif
\ No newline at end of file
......@@ -4,26 +4,14 @@
* VVV VVV A Virtual Acoustics (VA) | http://www.virtualacoustics.org
* VVV VVV AAA Licensed under the Apache License, Version 2.0
* VVV VVV AAA
* VVV VVV AAA Copyright 2015-2022
* VVV VVV AAA Copyright 2015-2023
* VVVVVV AAA Institute of Technical Acoustics (ITA)
* VVVV AAA RWTH Aachen University
*
* --------------------------------------------------------------------------------------------
*/
// Temporarily "disable" debug to include Python.
// This is done, so that the Python debug libraries are not needed, even when building
// this module in debug mode.
#ifdef _DEBUG
# define TMP_DEBUG
# undef _DEBUG
#endif
#include <Python.h>
#ifdef TMP_DEBUG
# define _DEBUG
# undef TMP_DEBUG
#endif
#include "common.hpp"
#include "vasingletondoc.hpp"
// All Python to VA methods. Also pulls in g_pVAError (Python error trace instance)
......@@ -217,7 +205,7 @@ static struct PyMethodDef va_methods[] = {
static struct PyModuleDef vamoduledef = { PyModuleDef_HEAD_INIT, "va", module_doc, -1, va_methods, NULL, NULL, NULL, NULL };
PyMODINIT_FUNC PyInit_va( void )
PyMODINIT_FUNC PyInit_VAPython( void )
{
PyObject* pModule = PyModule_Create( &vamoduledef );
g_pVAError = PyErr_NewException( "va.error", NULL, NULL );
......
......
......@@ -10,19 +10,10 @@
*
* --------------------------------------------------------------------------------------------
*/
#ifndef IW_VA_PYTHON_DOC
#define IW_VA_PYTHON_DOC
// Temporarily "disable" debug to include Python.
// This is done, so that the Python debug libraries are not needed, even when building
// this module in debug mode.
#ifdef _DEBUG
# define TMP_DEBUG
# undef _DEBUG
#endif
#include <Python.h>
#ifdef TMP_DEBUG
# define _DEBUG
# undef TMP_DEBUG
#endif
#include "common.hpp"
PyDoc_STRVAR( module_doc,
"connect(server, port) - connect to a VA server at given server and listening port\n"
......@@ -42,3 +33,5 @@ PyDoc_STRVAR( connect_doc,
" Remote server IP.\n"
" port\n"
" TCP/IP listening port, usually 12340." );
#endif
\ No newline at end of file
This diff is collapsed.
......@@ -5,7 +5,7 @@
import sys
sys.path.append( '../Lib/site-packages' ) # deploy structure
import va
import VAPython as va
print( "Testing va extension connection methods." )
......
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment