[DOC] write nealy all documentation on the class
This commit is contained in:
parent
4c3fe665cf
commit
3891b0ac52
19
monk_river.py
Normal file
19
monk_river.py
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import monkModule as module
|
||||||
|
import monkTools as tools
|
||||||
|
|
||||||
|
def get_desc():
|
||||||
|
return "river : Multiple flow input output audio"
|
||||||
|
|
||||||
|
|
||||||
|
def create():
|
||||||
|
# module name is 'edn' and type binary.
|
||||||
|
myModule = module.Module(__file__, 'river', 'LIBRARY')
|
||||||
|
# enable doculentation :
|
||||||
|
myModule.set_website("http://heeroyui.github.io/river/")
|
||||||
|
myModule.set_website_sources("http://github.com/heeroyui/river/")
|
||||||
|
myModule.set_path(tools.get_current_path(__file__) + "/river/")
|
||||||
|
myModule.set_path_general_doc(tools.get_current_path(__file__) + "/doc/")
|
||||||
|
# add the currrent module at the
|
||||||
|
return myModule
|
||||||
|
|
@ -35,6 +35,10 @@ namespace river {
|
|||||||
modeInterface_output,
|
modeInterface_output,
|
||||||
modeInterface_feedback,
|
modeInterface_feedback,
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @brief Interface is the basic handle to manage the input output stream
|
||||||
|
* @note To create this class see @ref river::Manager class
|
||||||
|
*/
|
||||||
class Interface : public std11::enable_shared_from_this<Interface> {
|
class Interface : public std11::enable_shared_from_this<Interface> {
|
||||||
friend class io::Node;
|
friend class io::Node;
|
||||||
friend class io::NodeAirTAudio;
|
friend class io::NodeAirTAudio;
|
||||||
@ -45,14 +49,34 @@ namespace river {
|
|||||||
uint32_t m_uid; //!< unique ID for interface
|
uint32_t m_uid; //!< unique ID for interface
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor (use factory)
|
||||||
*/
|
*/
|
||||||
Interface();
|
Interface();
|
||||||
|
/**
|
||||||
|
* @brief Initilize the Class (do all that is not manage by constructor) Call by factory.
|
||||||
|
* @param[in] _freq Frequency.
|
||||||
|
* @param[in] _map Channel map organization.
|
||||||
|
* @param[in] _format Sample format
|
||||||
|
* @param[in] _node Low level interface to connect the flow.
|
||||||
|
* @param[in] _config Special configuration of this interface.
|
||||||
|
* @return true Configuration done corectly.
|
||||||
|
* @return false the configuration has an error.
|
||||||
|
*/
|
||||||
bool init(float _freq,
|
bool init(float _freq,
|
||||||
const std::vector<audio::channel>& _map,
|
const std::vector<audio::channel>& _map,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
const std11::shared_ptr<river::io::Node>& _node,
|
const std11::shared_ptr<river::io::Node>& _node,
|
||||||
const std11::shared_ptr<const ejson::Object>& _config);
|
const std11::shared_ptr<const ejson::Object>& _config);
|
||||||
|
/**
|
||||||
|
* @brief Factory of this interface (called by class river::Manager)
|
||||||
|
* @param[in] _freq Frequency.
|
||||||
|
* @param[in] _map Channel map organization.
|
||||||
|
* @param[in] _format Sample format
|
||||||
|
* @param[in] _node Low level interface to connect the flow.
|
||||||
|
* @param[in] _config Special configuration of this interface.
|
||||||
|
* @return nullptr The configuration does not work.
|
||||||
|
* @return pointer The interface has been corectly created.
|
||||||
|
*/
|
||||||
static std11::shared_ptr<Interface> create(float _freq,
|
static std11::shared_ptr<Interface> create(float _freq,
|
||||||
const std::vector<audio::channel>& _map,
|
const std::vector<audio::channel>& _map,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
@ -64,16 +88,25 @@ namespace river {
|
|||||||
*/
|
*/
|
||||||
virtual ~Interface();
|
virtual ~Interface();
|
||||||
protected:
|
protected:
|
||||||
mutable std11::recursive_mutex m_mutex;
|
mutable std11::recursive_mutex m_mutex; //!< Local mutex to protect data
|
||||||
std11::shared_ptr<const ejson::Object> m_config;
|
std11::shared_ptr<const ejson::Object> m_config; //!< configuration set by the user.
|
||||||
protected:
|
protected:
|
||||||
enum modeInterface m_mode;
|
enum modeInterface m_mode; //!< interface type (input/output/feedback)
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get mode type of the current interface.
|
||||||
|
* @return The mode requested.
|
||||||
|
*/
|
||||||
enum modeInterface getMode() {
|
enum modeInterface getMode() {
|
||||||
return m_mode;
|
return m_mode;
|
||||||
}
|
}
|
||||||
drain::Process m_process;
|
protected:
|
||||||
|
drain::Process m_process; //!< Algorithme processing engine
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get the interface format configuration.
|
||||||
|
* @return The current format.
|
||||||
|
*/
|
||||||
const drain::IOFormatInterface& getInterfaceFormat() {
|
const drain::IOFormatInterface& getInterfaceFormat() {
|
||||||
if ( m_mode == modeInterface_input
|
if ( m_mode == modeInterface_input
|
||||||
|| m_mode == modeInterface_feedback) {
|
|| m_mode == modeInterface_feedback) {
|
||||||
@ -82,27 +115,47 @@ namespace river {
|
|||||||
return m_process.getInputConfig();
|
return m_process.getInputConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std11::shared_ptr<river::io::Node> m_node;
|
std11::shared_ptr<river::io::Node> m_node; //!< Hardware interface to/from stream audio flow.
|
||||||
protected:
|
protected:
|
||||||
std::string m_name;
|
std::string m_name; //!< Name of the interface.
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get interface name.
|
||||||
|
* @return The current name.
|
||||||
|
*/
|
||||||
virtual std::string getName() {
|
virtual std::string getName() {
|
||||||
return m_name;
|
return m_name;
|
||||||
};
|
};
|
||||||
|
/**
|
||||||
|
* @brief Set the interface name
|
||||||
|
* @param[in] _name new name of the interface
|
||||||
|
*/
|
||||||
virtual void setName(const std::string& _name) {
|
virtual void setName(const std::string& _name) {
|
||||||
m_name = _name;
|
m_name = _name;
|
||||||
};
|
};
|
||||||
/**
|
/**
|
||||||
* @brief set the read/write mode enable.
|
* @brief set the read/write mode enable.
|
||||||
|
* @note If you not set a output/input callback you must call this function.
|
||||||
*/
|
*/
|
||||||
virtual void setReadwrite();
|
virtual void setReadwrite();
|
||||||
/**
|
/**
|
||||||
* @brief When we want to implement a Callback Mode:
|
* @brief When we want to implement a Callback Mode:
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* @brief Set a callback on the write mode interface to know when data is needed in the buffer
|
||||||
|
* @param[in] _function Function to call
|
||||||
|
*/
|
||||||
virtual void setWriteCallback(drain::playbackFunctionWrite _function);
|
virtual void setWriteCallback(drain::playbackFunctionWrite _function);
|
||||||
|
/**
|
||||||
|
* @brief Set Output callback mode with the specify callback.
|
||||||
|
* @param[in] _function Function to call
|
||||||
|
*/
|
||||||
virtual void setOutputCallback(drain::playbackFunction _function);
|
virtual void setOutputCallback(drain::playbackFunction _function);
|
||||||
|
/**
|
||||||
|
* @brief Set Input callback mode with the specify callback.
|
||||||
|
* @param[in] _function Function to call
|
||||||
|
*/
|
||||||
virtual void setInputCallback(drain::recordFunction _function);
|
virtual void setInputCallback(drain::recordFunction _function);
|
||||||
/**
|
/**
|
||||||
* @brief Add a volume group of the current channel.
|
* @brief Add a volume group of the current channel.
|
||||||
@ -223,18 +276,52 @@ namespace river {
|
|||||||
*/
|
*/
|
||||||
virtual std11::chrono::system_clock::time_point getCurrentTime() const;
|
virtual std11::chrono::system_clock::time_point getCurrentTime() const;
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Node Call interface : Input interface node has new data.
|
||||||
|
* @param[in] _time Time where the first sample has been capture.
|
||||||
|
* @param[in] _data Pointer on the new data.
|
||||||
|
* @param[in] _nbChunk Number of chunk in the buffer.
|
||||||
|
*/
|
||||||
virtual void systemNewInputData(std11::chrono::system_clock::time_point _time, const void* _data, size_t _nbChunk);
|
virtual void systemNewInputData(std11::chrono::system_clock::time_point _time, const void* _data, size_t _nbChunk);
|
||||||
|
/**
|
||||||
|
* @brief Node Call interface: Output interface node need new data.
|
||||||
|
* @param[in] _time Time where the data might be played
|
||||||
|
* @param[in] _data Pointer on the data.
|
||||||
|
* @param[in] _nbChunk Number of chunk that might be write
|
||||||
|
* @param[in] _chunkSize Chunk size.
|
||||||
|
*/
|
||||||
virtual void systemNeedOutputData(std11::chrono::system_clock::time_point _time, void* _data, size_t _nbChunk, size_t _chunkSize);
|
virtual void systemNeedOutputData(std11::chrono::system_clock::time_point _time, void* _data, size_t _nbChunk, size_t _chunkSize);
|
||||||
|
/**
|
||||||
|
* @brief Node Call interface: A volume has change.
|
||||||
|
*/
|
||||||
virtual void systemVolumeChange();
|
virtual void systemVolumeChange();
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Create the dot in the FileNode stream.
|
||||||
|
* @param[in,out] _node File node to write data.
|
||||||
|
* @param[in] _nameIO Name to link the interface node
|
||||||
|
* @param[in] _isLink True if the node is connected on the current interface.
|
||||||
|
*/
|
||||||
virtual void generateDot(etk::FSNode& _node, const std::string& _nameIO, bool _isLink=true);
|
virtual void generateDot(etk::FSNode& _node, const std::string& _nameIO, bool _isLink=true);
|
||||||
|
/**
|
||||||
|
* @brief Get the current 'dot' name of the interface
|
||||||
|
* @return The anme requested.
|
||||||
|
*/
|
||||||
virtual std::string getDotNodeName() const;
|
virtual std::string getDotNodeName() const;
|
||||||
private:
|
protected:
|
||||||
//statusFunction m_statusFunction;
|
/**
|
||||||
public:
|
* @brief Interfanel generate of status
|
||||||
|
* @param[in] _origin status source
|
||||||
|
* @param[in] _status Event status
|
||||||
|
*/
|
||||||
void generateStatus(const std::string& _origin, const std::string& _status) {
|
void generateStatus(const std::string& _origin, const std::string& _status) {
|
||||||
m_process.generateStatus(_origin, _status);
|
m_process.generateStatus(_origin, _status);
|
||||||
}
|
}
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Set status callback
|
||||||
|
* @param[in] _newFunction Function to call
|
||||||
|
*/
|
||||||
void setStatusFunction(drain::statusFunction _newFunction) {
|
void setStatusFunction(drain::statusFunction _newFunction) {
|
||||||
m_process.setStatusFunction(_newFunction);
|
m_process.setStatusFunction(_newFunction);
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ namespace river {
|
|||||||
/**
|
/**
|
||||||
* @brief Audio interface manager : Single interface for every application that want to access on the Audio input/output
|
* @brief Audio interface manager : Single interface for every application that want to access on the Audio input/output
|
||||||
*/
|
*/
|
||||||
class Manager {
|
class Manager : public std11::enable_shared_from_this<Manager> {
|
||||||
private:
|
private:
|
||||||
const std::string& m_applicationUniqueId; //!< name of the application that open the Audio Interface.
|
const std::string& m_applicationUniqueId; //!< name of the application that open the Audio Interface.
|
||||||
std::vector<std11::weak_ptr<river::Interface> > m_listOpenInterface; //!< List of all open Stream.
|
std::vector<std11::weak_ptr<river::Interface> > m_listOpenInterface; //!< List of all open Stream.
|
||||||
@ -29,6 +29,11 @@ namespace river {
|
|||||||
*/
|
*/
|
||||||
Manager(const std::string& _applicationUniqueId);
|
Manager(const std::string& _applicationUniqueId);
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief factory of the manager. Every Application will have only one maager for all his flow. this permit to manage all of it
|
||||||
|
* @param[in] _applicationUniqueId Unique name of the application
|
||||||
|
* @return Pointer on the manager or nullptr if an error occured
|
||||||
|
*/
|
||||||
static std11::shared_ptr<river::Manager> create(const std::string& _applicationUniqueId);
|
static std11::shared_ptr<river::Manager> create(const std::string& _applicationUniqueId);
|
||||||
/**
|
/**
|
||||||
* @brief Destructor
|
* @brief Destructor
|
||||||
|
@ -16,5 +16,6 @@
|
|||||||
#undef RIVER_VERBOSE
|
#undef RIVER_VERBOSE
|
||||||
#undef RIVER_TODO
|
#undef RIVER_TODO
|
||||||
#undef RIVER_ASSERT
|
#undef RIVER_ASSERT
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -16,17 +16,57 @@ namespace river {
|
|||||||
namespace io {
|
namespace io {
|
||||||
class Node;
|
class Node;
|
||||||
class Manager;
|
class Manager;
|
||||||
|
/**
|
||||||
|
* @brief Group is contituate to manage some input and output in the same start and stop.
|
||||||
|
* It link N interface in a group. The start and the sopt is requested in Node inside the
|
||||||
|
* group they will start and stop when the first start is requested and stop when the last
|
||||||
|
* is stopped.
|
||||||
|
* @note For the Alsa interface a low level link is availlable with AirTAudio for Alsa (One thread)
|
||||||
|
*/
|
||||||
class Group : public std11::enable_shared_from_this<Group> {
|
class Group : public std11::enable_shared_from_this<Group> {
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Contructor. No special thing to do.
|
||||||
|
*/
|
||||||
Group() {}
|
Group() {}
|
||||||
~Group() {}
|
/**
|
||||||
private:
|
* @brief Destructor
|
||||||
std::vector< std11::shared_ptr<Node> > m_list;
|
*/
|
||||||
|
~Group() {
|
||||||
|
// TODO : ...
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
std::vector< std11::shared_ptr<Node> > m_list; //!< List of all node in the group
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Create a group with all node needed to syncronize together
|
||||||
|
* @param[in] _obj json document to create all the node in the group named _name
|
||||||
|
* @param[in] _name Name of the group to create
|
||||||
|
*/
|
||||||
void createFrom(const ejson::Document& _obj, const std::string& _name);
|
void createFrom(const ejson::Document& _obj, const std::string& _name);
|
||||||
|
/**
|
||||||
|
* @brief Get a node in the group (if the node is not in the group nothing append).
|
||||||
|
* @param[in] _name Name of the node requested.
|
||||||
|
* @return nullptr The node named _name was not found.
|
||||||
|
* @return pointer The node was find in this group.
|
||||||
|
*/
|
||||||
std11::shared_ptr<river::io::Node> getNode(const std::string& _name);
|
std11::shared_ptr<river::io::Node> getNode(const std::string& _name);
|
||||||
|
/**
|
||||||
|
* @brief Start the group.
|
||||||
|
* @note all sub-node will be started.
|
||||||
|
*/
|
||||||
void start();
|
void start();
|
||||||
|
/**
|
||||||
|
* @brief Stop the group.
|
||||||
|
* @note All sub-node will be stopped at the reserve order that they start.
|
||||||
|
*/
|
||||||
void stop();
|
void stop();
|
||||||
|
/**
|
||||||
|
* @brief Create the dot in the FileNode stream.
|
||||||
|
* @param[in,out] _node File node to write data.
|
||||||
|
* @param[in] _hardwareNode true if user want only display the hardware
|
||||||
|
* node and not the software node. false The oposite.
|
||||||
|
*/
|
||||||
void generateDot(etk::FSNode& _node, bool _hardwareNode);
|
void generateDot(etk::FSNode& _node, bool _hardwareNode);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -25,9 +25,13 @@
|
|||||||
namespace river {
|
namespace river {
|
||||||
namespace io {
|
namespace io {
|
||||||
class Node;
|
class Node;
|
||||||
class Manager {
|
/**
|
||||||
|
* @brief Internal sigleton of all Flow hadware and virtuals.
|
||||||
|
* @note this class will be initialize by the river::init() function at the start of the application.
|
||||||
|
*/
|
||||||
|
class Manager : public std11::enable_shared_from_this<Manager> {
|
||||||
private:
|
private:
|
||||||
mutable std11::recursive_mutex m_mutex;
|
mutable std11::recursive_mutex m_mutex; //!< prevent multiple access
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
@ -39,18 +43,39 @@ namespace river {
|
|||||||
* @brief Destructor
|
* @brief Destructor
|
||||||
*/
|
*/
|
||||||
~Manager();
|
~Manager();
|
||||||
|
/**
|
||||||
|
* @brief Called by river::init() to set the hardware configuration file.
|
||||||
|
* @param[in] _filename Name of the file to initialize.
|
||||||
|
*/
|
||||||
void init(const std::string& _filename);
|
void init(const std::string& _filename);
|
||||||
|
/**
|
||||||
|
* @brief Called by river::initString() to set the hardware configuration string.
|
||||||
|
* @param[in] _data json configuration string.
|
||||||
|
*/
|
||||||
void initString(const std::string& _data);
|
void initString(const std::string& _data);
|
||||||
|
/**
|
||||||
|
* @brief Called by river::inInit() to uninitialize all the low level interface.
|
||||||
|
*/
|
||||||
void unInit();
|
void unInit();
|
||||||
private:
|
private:
|
||||||
ejson::Document m_config; // harware configuration
|
ejson::Document m_config; //!< harware configuration
|
||||||
std::vector<std11::shared_ptr<river::io::Node> > m_listKeepAlive; //!< list of all Node that might be keep alive sone time
|
std::vector<std11::shared_ptr<river::io::Node> > m_listKeepAlive; //!< list of all Node that might be keep alive sone/all time
|
||||||
std::vector<std11::weak_ptr<river::io::Node> > m_list; //!< List of all IO node
|
std::vector<std11::weak_ptr<river::io::Node> > m_list; //!< List of all IO node
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get a node with his name (the name is set in the description file.
|
||||||
|
* @param[in] _name Name of the node
|
||||||
|
* @return Pointer on the noe or a nullptr if the node does not exist in the file or an error occured.
|
||||||
|
*/
|
||||||
std11::shared_ptr<river::io::Node> getNode(const std::string& _name);
|
std11::shared_ptr<river::io::Node> getNode(const std::string& _name);
|
||||||
private:
|
private:
|
||||||
std::vector<std11::shared_ptr<drain::VolumeElement> > m_volumeGroup;
|
std::vector<std11::shared_ptr<drain::VolumeElement> > m_volumeGroup; //!< List of All global volume in the Low level interface.
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get a volume in the global list of vilume
|
||||||
|
* @param[in] _name Name of the volume.
|
||||||
|
* @return pointer on the requested volume (create it if does not exist). nullptr if the name is empty.
|
||||||
|
*/
|
||||||
std11::shared_ptr<drain::VolumeElement> getVolumeGroup(const std::string& _name);
|
std11::shared_ptr<drain::VolumeElement> getVolumeGroup(const std::string& _name);
|
||||||
/**
|
/**
|
||||||
* @brief Get all input audio stream.
|
* @brief Get all input audio stream.
|
||||||
@ -103,6 +128,11 @@ namespace river {
|
|||||||
void generateDot(const std::string& _filename);
|
void generateDot(const std::string& _filename);
|
||||||
private:
|
private:
|
||||||
std::map<std::string, std11::shared_ptr<river::io::Group> > m_listGroup; //!< List of all groups
|
std::map<std::string, std11::shared_ptr<river::io::Group> > m_listGroup; //!< List of all groups
|
||||||
|
/**
|
||||||
|
* @brief get a low level interface group.
|
||||||
|
* @param[in] _name Name of the group.
|
||||||
|
* @return Pointer on the requested group or nullptr if the group does not existed.
|
||||||
|
*/
|
||||||
std11::shared_ptr<river::io::Group> getGroup(const std::string& _name);
|
std11::shared_ptr<river::io::Group> getGroup(const std::string& _name);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -189,11 +189,11 @@ void river::io::Node::volumeChange() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t river::io::Node::newInput(const void* _inputBuffer,
|
void river::io::Node::newInput(const void* _inputBuffer,
|
||||||
uint32_t _nbChunk,
|
uint32_t _nbChunk,
|
||||||
const std11::chrono::system_clock::time_point& _time) {
|
const std11::chrono::system_clock::time_point& _time) {
|
||||||
if (_inputBuffer == nullptr) {
|
if (_inputBuffer == nullptr) {
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
const int16_t* inputBuffer = static_cast<const int16_t *>(_inputBuffer);
|
const int16_t* inputBuffer = static_cast<const int16_t *>(_inputBuffer);
|
||||||
for (size_t iii=0; iii< m_list.size(); ++iii) {
|
for (size_t iii=0; iii< m_list.size(); ++iii) {
|
||||||
@ -207,14 +207,14 @@ int32_t river::io::Node::newInput(const void* _inputBuffer,
|
|||||||
m_list[iii]->systemNewInputData(_time, inputBuffer, _nbChunk);
|
m_list[iii]->systemNewInputData(_time, inputBuffer, _nbChunk);
|
||||||
}
|
}
|
||||||
RIVER_VERBOSE("data Input size request :" << _nbChunk << " [ END ]");
|
RIVER_VERBOSE("data Input size request :" << _nbChunk << " [ END ]");
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t river::io::Node::newOutput(void* _outputBuffer,
|
void river::io::Node::newOutput(void* _outputBuffer,
|
||||||
uint32_t _nbChunk,
|
uint32_t _nbChunk,
|
||||||
const std11::chrono::system_clock::time_point& _time) {
|
const std11::chrono::system_clock::time_point& _time) {
|
||||||
if (_outputBuffer == nullptr) {
|
if (_outputBuffer == nullptr) {
|
||||||
return -1;
|
return;
|
||||||
}
|
}
|
||||||
std::vector<int32_t> output;
|
std::vector<int32_t> output;
|
||||||
RIVER_VERBOSE("resize=" << _nbChunk*m_process.getInputConfig().getMap().size());
|
RIVER_VERBOSE("resize=" << _nbChunk*m_process.getInputConfig().getMap().size());
|
||||||
@ -259,7 +259,7 @@ int32_t river::io::Node::newOutput(void* _outputBuffer,
|
|||||||
m_list[iii]->systemNewInputData(_time, _outputBuffer, _nbChunk);
|
m_list[iii]->systemNewInputData(_time, _outputBuffer, _nbChunk);
|
||||||
}
|
}
|
||||||
RIVER_VERBOSE("data Output size request :" << _nbChunk << " [ END ]");
|
RIVER_VERBOSE("data Output size request :" << _nbChunk << " [ END ]");
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void link(etk::FSNode& _node, const std::string& _first, const std::string& _op, const std::string& _second) {
|
static void link(etk::FSNode& _node, const std::string& _first, const std::string& _op, const std::string& _second) {
|
||||||
|
129
river/io/Node.h
129
river/io/Node.h
@ -27,13 +27,19 @@ namespace river {
|
|||||||
namespace io {
|
namespace io {
|
||||||
class Manager;
|
class Manager;
|
||||||
class Group;
|
class Group;
|
||||||
|
/**
|
||||||
|
* @brief A node is the base for input/output interface. When a output id declared, we automaticly have a feedback associated.
|
||||||
|
* this manage the muxing of data for output an the demuxing for input.
|
||||||
|
*/
|
||||||
class Node : public std11::enable_shared_from_this<Node> {
|
class Node : public std11::enable_shared_from_this<Node> {
|
||||||
friend class river::io::Group;
|
friend class river::io::Group;
|
||||||
protected:
|
protected:
|
||||||
uint32_t m_uid; // uniqueNodeID
|
uint32_t m_uid; //!< uniqueNodeID use for debug an dot generation.
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
* @brief Constructor
|
* @brief Constructor
|
||||||
|
* @param[in] _name Name of the node.
|
||||||
|
* @param[in] _config Configuration of the node.
|
||||||
*/
|
*/
|
||||||
Node(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config);
|
Node(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config);
|
||||||
public:
|
public:
|
||||||
@ -41,15 +47,24 @@ namespace river {
|
|||||||
* @brief Destructor
|
* @brief Destructor
|
||||||
*/
|
*/
|
||||||
virtual ~Node();
|
virtual ~Node();
|
||||||
|
/**
|
||||||
|
* @brief Get the status of this node acces on harware or acces on other node (virtual).
|
||||||
|
* @return true This is an harware interface.
|
||||||
|
* @return false this is a virtual interface.
|
||||||
|
*/
|
||||||
virtual bool isHarwareNode() {
|
virtual bool isHarwareNode() {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
mutable std11::mutex m_mutex;
|
mutable std11::mutex m_mutex; //!< prevent open/close/write/read access that is multi-threaded.
|
||||||
std11::shared_ptr<const ejson::Object> m_config;
|
std11::shared_ptr<const ejson::Object> m_config; //!< configuration description.
|
||||||
protected:
|
protected:
|
||||||
drain::Process m_process;
|
drain::Process m_process; //!< Low level algorithms
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get the uper client interface configuration.
|
||||||
|
* @return process configuration.
|
||||||
|
*/
|
||||||
const drain::IOFormatInterface& getInterfaceFormat() {
|
const drain::IOFormatInterface& getInterfaceFormat() {
|
||||||
if (m_isInput == true) {
|
if (m_isInput == true) {
|
||||||
return m_process.getOutputConfig();
|
return m_process.getOutputConfig();
|
||||||
@ -57,6 +72,10 @@ namespace river {
|
|||||||
return m_process.getInputConfig();
|
return m_process.getInputConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @brief Get the harware client interface configuration.
|
||||||
|
* @return process configuration.
|
||||||
|
*/
|
||||||
const drain::IOFormatInterface& getHarwareFormat() {
|
const drain::IOFormatInterface& getHarwareFormat() {
|
||||||
if (m_isInput == true) {
|
if (m_isInput == true) {
|
||||||
return m_process.getInputConfig();
|
return m_process.getInputConfig();
|
||||||
@ -65,62 +84,138 @@ namespace river {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
|
std11::shared_ptr<drain::VolumeElement> m_volume; //!< if a volume is set it is set here ... for hardware interface only.
|
||||||
std11::shared_ptr<drain::VolumeElement> m_volume; //!< if a volume is set it is set here ...
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<std11::weak_ptr<river::Interface> > m_listAvaillable; //!< List of all interface that exist on this Node
|
std::vector<std11::weak_ptr<river::Interface> > m_listAvaillable; //!< List of all interface that exist on this Node
|
||||||
std::vector<std11::shared_ptr<river::Interface> > m_list;
|
std::vector<std11::shared_ptr<river::Interface> > m_list; //!< List of all connected interface at this node.
|
||||||
|
/**
|
||||||
|
* @brief Get the number of interface with a specific type.
|
||||||
|
* @param[in] _interfaceType Type of the interface.
|
||||||
|
* @return Number of interface connected.
|
||||||
|
*/
|
||||||
size_t getNumberOfInterface(enum river::modeInterface _interfaceType);
|
size_t getNumberOfInterface(enum river::modeInterface _interfaceType);
|
||||||
|
/**
|
||||||
|
* @brief Get the number of interface with a specific type that can connect on the Node.
|
||||||
|
* @param[in] _interfaceType Type of the interface.
|
||||||
|
* @return Number of interface that can connect.
|
||||||
|
*/
|
||||||
size_t getNumberOfInterfaceAvaillable(enum river::modeInterface _interfaceType);
|
size_t getNumberOfInterfaceAvaillable(enum river::modeInterface _interfaceType);
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get the number of interface connected
|
||||||
|
* @return Number of interfaces.
|
||||||
|
*/
|
||||||
size_t getNumberOfInterface() {
|
size_t getNumberOfInterface() {
|
||||||
return m_list.size();
|
return m_list.size();
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Register an interface that can connect on it. (might be done in the Interface Init)
|
||||||
|
* @note We keep a std::weak_ptr. this is the reason why we do not have a remove.
|
||||||
|
* @param[in] _interface Pointer on the interface to register.
|
||||||
|
*/
|
||||||
void registerAsRemote(const std11::shared_ptr<river::Interface>& _interface);
|
void registerAsRemote(const std11::shared_ptr<river::Interface>& _interface);
|
||||||
|
/**
|
||||||
|
* @brief Request this interface might receve/send dat on the flow. (start/resume)
|
||||||
|
* @param[in] _interface Pointer on the interface to register.
|
||||||
|
*/
|
||||||
void interfaceAdd(const std11::shared_ptr<river::Interface>& _interface);
|
void interfaceAdd(const std11::shared_ptr<river::Interface>& _interface);
|
||||||
|
/**
|
||||||
|
* @brief Un-register the interface as an availlable read/write interface. (suspend/stop)
|
||||||
|
* @param[in] _interface Pointer on the interface to register.
|
||||||
|
*/
|
||||||
void interfaceRemove(const std11::shared_ptr<river::Interface>& _interface);
|
void interfaceRemove(const std11::shared_ptr<river::Interface>& _interface);
|
||||||
protected:
|
protected:
|
||||||
std::string m_name; //!< Harware.json configuration name
|
std::string m_name; //!< Name of the interface
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Get the interface name.
|
||||||
|
* @return Current name.
|
||||||
|
*/
|
||||||
const std::string& getName() {
|
const std::string& getName() {
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
bool m_isInput;
|
bool m_isInput; //!< sense of the stream
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Check if it is an input stream
|
||||||
|
* @return true if it is an input/ false otherwise
|
||||||
|
*/
|
||||||
bool isInput() {
|
bool isInput() {
|
||||||
return m_isInput;
|
return m_isInput;
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* @brief Check if it is an output stream
|
||||||
|
* @return true if it is an output/ false otherwise
|
||||||
|
*/
|
||||||
bool isOutput() {
|
bool isOutput() {
|
||||||
return !m_isInput;
|
return !m_isInput;
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
std11::weak_ptr<river::io::Group> m_group;
|
std11::weak_ptr<river::io::Group> m_group; //!< reference on the group. If available.
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Set this node in a low level group.
|
||||||
|
* @param[in] _group Group reference.
|
||||||
|
*/
|
||||||
void setGroup(std11::shared_ptr<river::io::Group> _group) {
|
void setGroup(std11::shared_ptr<river::io::Group> _group) {
|
||||||
m_group = _group;
|
m_group = _group;
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
|
/**
|
||||||
|
* @brief Start the flow in the group (start if no group)
|
||||||
|
*/
|
||||||
void startInGroup();
|
void startInGroup();
|
||||||
|
/**
|
||||||
|
* @brief Stop the flow in the group (stop if no group)
|
||||||
|
*/
|
||||||
void stopInGroup();
|
void stopInGroup();
|
||||||
|
/**
|
||||||
|
* @brief Real start of the stream
|
||||||
|
*/
|
||||||
virtual void start() = 0;
|
virtual void start() = 0;
|
||||||
|
/**
|
||||||
|
* @brief Real stop of the stream
|
||||||
|
*/
|
||||||
virtual void stop() = 0;
|
virtual void stop() = 0;
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief If this iss an hardware interface we can have a resuest of the volume stage:
|
||||||
|
* @return pointer on the requested volume.
|
||||||
|
*/
|
||||||
const std11::shared_ptr<drain::VolumeElement>& getVolume() {
|
const std11::shared_ptr<drain::VolumeElement>& getVolume() {
|
||||||
return m_volume;
|
return m_volume;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Called when a group wolume has been change to update all volume stage.
|
||||||
|
*/
|
||||||
void volumeChange();
|
void volumeChange();
|
||||||
protected:
|
protected:
|
||||||
int32_t newInput(const void* _inputBuffer,
|
/**
|
||||||
uint32_t _nbChunk,
|
* @brief Call by child classes to process data in all interface linked on the current Node. Have new input to process.
|
||||||
const std11::chrono::system_clock::time_point& _time);
|
* @param[in] _inputBuffer Pointer on the data.
|
||||||
int32_t newOutput(void* _outputBuffer,
|
* @param[in] _nbChunk Number of chunk in the buffer.
|
||||||
uint32_t _nbChunk,
|
* @param[in] _time Time where the first sample has been capture.
|
||||||
const std11::chrono::system_clock::time_point& _time);
|
*/
|
||||||
|
void newInput(const void* _inputBuffer,
|
||||||
|
uint32_t _nbChunk,
|
||||||
|
const std11::chrono::system_clock::time_point& _time);
|
||||||
|
/**
|
||||||
|
* @brief Call by child classes to process data in all interface linked on the current Node. Have new output to get. this call the feedback too.
|
||||||
|
* @param[in,out] _outputBuffer Pointer on the buffer to write the data.
|
||||||
|
* @param[in] _nbChunk Number of chunk to write in the buffer.
|
||||||
|
* @param[in] _time Time where the data might be played.
|
||||||
|
*/
|
||||||
|
void newOutput(void* _outputBuffer,
|
||||||
|
uint32_t _nbChunk,
|
||||||
|
const std11::chrono::system_clock::time_point& _time);
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Generate the node dot file section
|
||||||
|
* @param[in] _node File node to generate the data.
|
||||||
|
*/
|
||||||
virtual void generateDot(etk::FSNode& _node);
|
virtual void generateDot(etk::FSNode& _node);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -197,10 +197,8 @@ void river::io::NodeAEC::onDataReceivedFeedBack(const void* _data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void river::io::NodeAEC::process() {
|
void river::io::NodeAEC::process() {
|
||||||
if (m_bufferMicrophone.getSize() <= 256) {
|
if ( m_bufferMicrophone.getSize() <= 256
|
||||||
return;
|
|| m_bufferFeedBack.getSize() <= 256) {
|
||||||
}
|
|
||||||
if (m_bufferFeedBack.getSize() <= 256) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std11::chrono::system_clock::time_point MicTime = m_bufferMicrophone.getReadTimeStamp();
|
std11::chrono::system_clock::time_point MicTime = m_bufferMicrophone.getReadTimeStamp();
|
||||||
|
@ -21,6 +21,11 @@ namespace river {
|
|||||||
*/
|
*/
|
||||||
NodeAEC(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config);
|
NodeAEC(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config);
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Factory of this Virtual Node.
|
||||||
|
* @param[in] _name Name of the node.
|
||||||
|
* @param[in] _config Configuration of the node.
|
||||||
|
*/
|
||||||
static std11::shared_ptr<NodeAEC> create(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config);
|
static std11::shared_ptr<NodeAEC> create(const std::string& _name, const std11::shared_ptr<const ejson::Object>& _config);
|
||||||
/**
|
/**
|
||||||
* @brief Destructor
|
* @brief Destructor
|
||||||
@ -29,29 +34,58 @@ namespace river {
|
|||||||
protected:
|
protected:
|
||||||
virtual void start();
|
virtual void start();
|
||||||
virtual void stop();
|
virtual void stop();
|
||||||
std11::shared_ptr<river::Interface> m_interfaceMicrophone;
|
std11::shared_ptr<river::Interface> m_interfaceMicrophone; //!< Interface on the Microphone.
|
||||||
std11::shared_ptr<river::Interface> m_interfaceFeedBack;
|
std11::shared_ptr<river::Interface> m_interfaceFeedBack; //!< Interface on the feedback of speaker.
|
||||||
|
/**
|
||||||
|
* @brief Internal: create an input with the specific parameter:
|
||||||
|
* @param[in] _freq Frequency.
|
||||||
|
* @param[in] _map Channel map organization.
|
||||||
|
* @param[in] _format Sample format
|
||||||
|
* @param[in] _streamName
|
||||||
|
* @param[in] _name
|
||||||
|
* @return Interfae Pointer.
|
||||||
|
*/
|
||||||
std11::shared_ptr<river::Interface> createInput(float _freq,
|
std11::shared_ptr<river::Interface> createInput(float _freq,
|
||||||
const std::vector<audio::channel>& _map,
|
const std::vector<audio::channel>& _map,
|
||||||
audio::format _format,
|
audio::format _format,
|
||||||
const std::string& _streamName,
|
const std::string& _streamName,
|
||||||
const std::string& _name);
|
const std::string& _name);
|
||||||
|
/**
|
||||||
|
* @brief Stream data input callback
|
||||||
|
* @todo : copy doc ..
|
||||||
|
*/
|
||||||
void onDataReceivedMicrophone(const void* _data,
|
void onDataReceivedMicrophone(const void* _data,
|
||||||
const std11::chrono::system_clock::time_point& _time,
|
const std11::chrono::system_clock::time_point& _time,
|
||||||
size_t _nbChunk,
|
size_t _nbChunk,
|
||||||
enum audio::format _format,
|
enum audio::format _format,
|
||||||
uint32_t _frequency,
|
uint32_t _frequency,
|
||||||
const std::vector<audio::channel>& _map);
|
const std::vector<audio::channel>& _map);
|
||||||
|
/**
|
||||||
|
* @brief Stream data input callback
|
||||||
|
* @todo : copy doc ..
|
||||||
|
*/
|
||||||
void onDataReceivedFeedBack(const void* _data,
|
void onDataReceivedFeedBack(const void* _data,
|
||||||
const std11::chrono::system_clock::time_point& _time,
|
const std11::chrono::system_clock::time_point& _time,
|
||||||
size_t _nbChunk,
|
size_t _nbChunk,
|
||||||
enum audio::format _format,
|
enum audio::format _format,
|
||||||
uint32_t _frequency,
|
uint32_t _frequency,
|
||||||
const std::vector<audio::channel>& _map);
|
const std::vector<audio::channel>& _map);
|
||||||
drain::CircularBuffer m_bufferMicrophone;
|
protected:
|
||||||
drain::CircularBuffer m_bufferFeedBack;
|
drain::CircularBuffer m_bufferMicrophone; //!< temporary buffer to synchronize data.
|
||||||
|
drain::CircularBuffer m_bufferFeedBack; //!< temporary buffer to synchronize data.
|
||||||
std11::chrono::nanoseconds m_sampleTime; //!< represent the sample time at the specify frequency.
|
std11::chrono::nanoseconds m_sampleTime; //!< represent the sample time at the specify frequency.
|
||||||
|
/**
|
||||||
|
* @brief Process synchronization on the 2 flow.
|
||||||
|
*/
|
||||||
void process();
|
void process();
|
||||||
|
/**
|
||||||
|
* @brief Process algorithm on the current 2 syncronize flow.
|
||||||
|
* @param[in] _dataMic Pointer in the Microphione interface.
|
||||||
|
* @param[in] _dataFB Pointer on the beedback buffer.
|
||||||
|
* @param[in] _nbChunk Number of chunk to process.
|
||||||
|
* @param[in] _time Time on the firsta sample that data has been captured.
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
void processAEC(void* _dataMic, void* _dataFB, uint32_t _nbChunk, const std11::chrono::system_clock::time_point& _time);
|
void processAEC(void* _dataMic, void* _dataFB, uint32_t _nbChunk, const std11::chrono::system_clock::time_point& _time);
|
||||||
public:
|
public:
|
||||||
virtual void generateDot(etk::FSNode& _node);
|
virtual void generateDot(etk::FSNode& _node);
|
||||||
|
@ -23,25 +23,6 @@ static std::string asString(const std11::chrono::system_clock::time_point& tp) {
|
|||||||
return ts;
|
return ts;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t river::io::NodeAirTAudio::duplexCallback(const void* _inputBuffer,
|
|
||||||
const std11::chrono::system_clock::time_point& _timeInput,
|
|
||||||
void* _outputBuffer,
|
|
||||||
const std11::chrono::system_clock::time_point& _timeOutput,
|
|
||||||
uint32_t _nbChunk,
|
|
||||||
const std::vector<airtaudio::status>& _status) {
|
|
||||||
std11::unique_lock<std11::mutex> lock(m_mutex);
|
|
||||||
// TODO : Manage status ...
|
|
||||||
if (_inputBuffer != nullptr) {
|
|
||||||
RIVER_VERBOSE("data Input size request :" << _nbChunk << " [BEGIN] status=" << _status << " nbIO=" << m_list.size());
|
|
||||||
newInput(_inputBuffer, _nbChunk, _timeInput);
|
|
||||||
}
|
|
||||||
if (_outputBuffer != nullptr) {
|
|
||||||
RIVER_VERBOSE("data Output size request :" << _nbChunk << " [BEGIN] status=" << _status << " nbIO=" << m_list.size());
|
|
||||||
newOutput(_outputBuffer, _nbChunk, _timeOutput);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t river::io::NodeAirTAudio::recordCallback(const void* _inputBuffer,
|
int32_t river::io::NodeAirTAudio::recordCallback(const void* _inputBuffer,
|
||||||
const std11::chrono::system_clock::time_point& _timeInput,
|
const std11::chrono::system_clock::time_point& _timeInput,
|
||||||
uint32_t _nbChunk,
|
uint32_t _nbChunk,
|
||||||
|
@ -15,7 +15,10 @@ namespace river {
|
|||||||
namespace io {
|
namespace io {
|
||||||
class Manager;
|
class Manager;
|
||||||
class Group;
|
class Group;
|
||||||
class NodeAirTAudio : public Node {
|
/**
|
||||||
|
* @brief Low level node that is manage on the interface with the extern lib airtaudio
|
||||||
|
*/
|
||||||
|
class NodeAirTAudio : public river::io::Node {
|
||||||
friend class river::io::Group;
|
friend class river::io::Group;
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
@ -32,20 +35,30 @@ namespace river {
|
|||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
protected:
|
protected:
|
||||||
airtaudio::Interface m_adac; //!< Real audio interface
|
airtaudio::Interface m_adac; //!< Real airtaudio interface
|
||||||
airtaudio::DeviceInfo m_info;
|
airtaudio::DeviceInfo m_info; //!< information on the stream.
|
||||||
unsigned int m_rtaudioFrameSize;
|
unsigned int m_rtaudioFrameSize; // DEPRECATED soon...
|
||||||
public:
|
public:
|
||||||
int32_t duplexCallback(const void* _inputBuffer,
|
/**
|
||||||
const std11::chrono::system_clock::time_point& _timeInput,
|
* @brief Input Callback . Have recaive new data to process.
|
||||||
void* _outputBuffer,
|
* @param[in] _inputBuffer Pointer on the data buffer.
|
||||||
const std11::chrono::system_clock::time_point& _timeOutput,
|
* @param[in] _timeInput Time on the fist sample has been recorded.
|
||||||
uint32_t _nbChunk,
|
* @param[in] _nbChunk Number of chunk in the buffer
|
||||||
const std::vector<airtaudio::status>& _status);
|
* @param[in] _status DEPRECATED soon
|
||||||
|
* @return DEPRECATED soon
|
||||||
|
*/
|
||||||
int32_t recordCallback(const void* _inputBuffer,
|
int32_t recordCallback(const void* _inputBuffer,
|
||||||
const std11::chrono::system_clock::time_point& _timeInput,
|
const std11::chrono::system_clock::time_point& _timeInput,
|
||||||
uint32_t _nbChunk,
|
uint32_t _nbChunk,
|
||||||
const std::vector<airtaudio::status>& _status);
|
const std::vector<airtaudio::status>& _status);
|
||||||
|
/**
|
||||||
|
* @brief Playback callback. Request new data on output
|
||||||
|
* @param[in,out] _outputBuffer Pointer on the buffer to fill data.
|
||||||
|
* @param[in] _timeOutput Time on wich the data might be played.
|
||||||
|
* @param[in] _nbChunk Number of chunk in the buffer
|
||||||
|
* @param[in] _status DEPRECATED soon
|
||||||
|
* @return DEPRECATED soon
|
||||||
|
*/
|
||||||
int32_t playbackCallback(void* _outputBuffer,
|
int32_t playbackCallback(void* _outputBuffer,
|
||||||
const std11::chrono::system_clock::time_point& _timeOutput,
|
const std11::chrono::system_clock::time_point& _timeOutput,
|
||||||
uint32_t _nbChunk,
|
uint32_t _nbChunk,
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
namespace river {
|
namespace river {
|
||||||
namespace io {
|
namespace io {
|
||||||
class Manager;
|
class Manager;
|
||||||
|
//! @not-in-doc
|
||||||
class NodePortAudio : public Node {
|
class NodePortAudio : public Node {
|
||||||
protected:
|
protected:
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user