Compare commits
No commits in common. "gh-pages" and "main" have entirely different histories.
64
.gitignore
vendored
Normal file
64
.gitignore
vendored
Normal file
@ -0,0 +1,64 @@
|
||||
|
||||
###################################
|
||||
# folders
|
||||
###################################
|
||||
CVS
|
||||
.svn
|
||||
Object_*
|
||||
doxygen/API/
|
||||
doxygen/ALL/
|
||||
|
||||
###################################
|
||||
# backup files
|
||||
###################################
|
||||
*~
|
||||
*.swp
|
||||
*.old
|
||||
*.bck
|
||||
|
||||
###################################
|
||||
# Compiled source #
|
||||
###################################
|
||||
*.com
|
||||
*.class
|
||||
*.dll
|
||||
*.exe
|
||||
*.o
|
||||
*.so
|
||||
*.pyc
|
||||
tags
|
||||
#ewol
|
||||
out
|
||||
ewol_debug
|
||||
ewol_release
|
||||
|
||||
###################################
|
||||
# Packages #
|
||||
###################################
|
||||
# it's better to unpack these files and commit the raw source
|
||||
# git has its own built in compression methods
|
||||
*.7z
|
||||
*.dmg
|
||||
*.gz
|
||||
*.iso
|
||||
*.jar
|
||||
*.rar
|
||||
*.tar
|
||||
*.zip
|
||||
|
||||
###################################
|
||||
# Logs and databases #
|
||||
###################################
|
||||
*.log
|
||||
*.sql
|
||||
*.sqlite
|
||||
|
||||
###################################
|
||||
# OS generated files #
|
||||
###################################
|
||||
.DS_Store?
|
||||
ehthumbs.db
|
||||
Icon?
|
||||
Thumbs.db
|
||||
Sources/libewol/ewol/os/AndroidAbstraction.cpp
|
||||
org_ewol_EwolConstants.h
|
88
.travis.yml
88
.travis.yml
@ -1,11 +1,7 @@
|
||||
language:
|
||||
- cpp
|
||||
language: cpp
|
||||
|
||||
sudo: false
|
||||
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
sudo: required
|
||||
dist: trusty
|
||||
|
||||
branches:
|
||||
only:
|
||||
@ -18,33 +14,81 @@ addons:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.9
|
||||
- expect
|
||||
- binutils-mingw-w64-x86-64 # 64bit MinGW
|
||||
- gcc-mingw-w64-x86-64
|
||||
- g++-mingw-w64-x86-64
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- os: linux
|
||||
env: CONF=release BUILDER=gcc TARGET=Linux TAG=Linux COMPILATOR_OPTION="--compilator-version=4.9" GCOV=--gcov
|
||||
compiler: gcc
|
||||
- os: linux
|
||||
env: CONF=debug BUILDER=clang TARGET=Linux
|
||||
compiler: clang
|
||||
- os: linux
|
||||
env: CONF=release BUILDER=gcc TARGET=Windows TAG=Mingw
|
||||
compiler: x86_64-w64-mingw32-gcc
|
||||
- os: linux
|
||||
env: CONF=release BUILDER=gcc TARGET=Android TAG=Android DISABLE_PACKAGE=-p
|
||||
compiler: gcc
|
||||
- os: osx
|
||||
env: CONF=release BUILDER=clang TARGET=MacOs TAG=MacOs
|
||||
compiler: clang
|
||||
- os: osx
|
||||
env: CONF=release BUILDER=clang TARGET=IOs TAG=IOs
|
||||
compiler: clang
|
||||
|
||||
|
||||
install:
|
||||
- cd ..
|
||||
- pip install --user lutin
|
||||
|
||||
env:
|
||||
- CONF=debug BOARD=Linux BUILDER=clang GCOV=
|
||||
- CONF=release BOARD=Linux BUILDER=clang GCOV=
|
||||
- CONF=debug BOARD=Linux BUILDER=gcc GCOV=
|
||||
- CONF=release BOARD=Linux BUILDER=gcc GCOV=
|
||||
- CONF=debug BOARD=Linux BUILDER=gcc GCOV=--gcov
|
||||
- if [ "$TAG" == "Android" ]; then
|
||||
git clone --depth 1 --branch master https://github.com/HeeroYui/android-download-tool;
|
||||
./android-download-tool/dl-android.sh;
|
||||
fi
|
||||
- git clone --depth 1 --branch master https://github.com/atria-soft/ci.git
|
||||
- cd -
|
||||
|
||||
before_script:
|
||||
- cd ..
|
||||
- wget http://atria-soft.com/ci/coverage_send.py
|
||||
- wget http://atria-soft.com/ci/test_send.py
|
||||
- wget http://atria-soft.com/ci/warning_send.py
|
||||
- git clone https://github.com/atria-soft/etk.git
|
||||
- git clone https://github.com/musicdsp/audio.git
|
||||
- git clone https://github.com/atria-soft/etk.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/elog.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/ememory.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/echrono.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/ethread.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/ejson.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/atria-soft/jvm-basics.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/musicdsp/audio.git -b $TRAVIS_BRANCH
|
||||
- git clone https://github.com/generic-library/gtest-lutin.git --recursive
|
||||
- git clone https://github.com/generic-library/z-lutin.git --recursive
|
||||
- pwd
|
||||
- ls -l
|
||||
- if [ "$BUILDER" == "gcc" ]; then COMPILATOR_OPTION="--compilator-version=4.9"; else COMPILATOR_OPTION=""; fi
|
||||
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then
|
||||
export PATH=$PATH:/Users/travis/Library/Python/2.7/bin/;
|
||||
fi
|
||||
- ./ci/build_send.py --tag=$TAG --status=START;
|
||||
|
||||
|
||||
script:
|
||||
- lutin -w -j4 -C -P -c $BUILDER $COMPILATOR_OPTION -m $CONF $GCOV -p audio-orchestra
|
||||
# - ./out/Linux_x86_64/$CONF/staging/$BUILDER/audio-orchestra/usr/bin/audio-orchestra -l6
|
||||
- lutin -w -j4 -C -P -t$TARGET -c $BUILDER $COMPILATOR_OPTION $BUS -m $CONF $GCOV $DISABLE_PACKAGE audio-orchestra; STATUS=$?
|
||||
- ./ci/build_send.py --tag=$TAG --status="$STATUS";
|
||||
|
||||
after_script:
|
||||
- if [ "$GCOV" != "" ]; then
|
||||
./ci/warning_send.py --find-path ./out/Linux_x86_64/$CONF/build/$BUILDER/audio-orchestra/;
|
||||
fi
|
||||
#- lutin -w -j4 -C -P -t$TARGET -c $BUILDER $COMPILATOR_OPTION $BUS -m $CONF $GCOV $DISABLE_PACKAGE audio-orchestra-test?run:--elog-level=3 | tee out_test.txt
|
||||
#- if [ "$GCOV" != "" ]; then
|
||||
# ./ci/test_send.py --file=out_test.txt;
|
||||
# lutin -C -P -t $TARGET -c $BUILDER $COMPILATOR_OPTION $BUS -m $CONF -p audio-orchestra?gcov;
|
||||
# ./ci/coverage_send.py --json=out/Linux_x86_64/$CONF/build/$BUILDER/audio-orchestra/audio-orchestra_coverage.json;
|
||||
# fi
|
||||
|
||||
notifications:
|
||||
email:
|
||||
- yui.heero@gmail.com
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
------------------------------
|
||||
|
||||
Nothing else ...
|
||||
# audio-orchestra
|
||||
(MIT) audio: backend to acces hardware access (Fork of the original RTAudio lib)
|
||||
|
||||
[![Build Status](https://travis-ci.org/musicdsp/audio-orchestra.svg?branch=master)](https://travis-ci.org/musicdsp/audio-orchestra)
|
||||
|
13
android/org/musicdsp/orchestra/OrchestraConstants.java
Normal file
13
android/org/musicdsp/orchestra/OrchestraConstants.java
Normal file
@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @author Edouard DUPIN
|
||||
*
|
||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||
*
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
package org.musicdsp.orchestra;
|
||||
|
||||
public interface OrchestraConstants {
|
||||
public static final int BUFFER_SIZE = 512;
|
||||
}
|
119
android/org/musicdsp/orchestra/OrchestraInterfaceInput.java
Normal file
119
android/org/musicdsp/orchestra/OrchestraInterfaceInput.java
Normal file
@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @author Edouard DUPIN, Kevin BILLONNEAU
|
||||
*
|
||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||
*
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
package org.musicdsp.orchestra;
|
||||
import android.media.AudioRecord;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioRecord;
|
||||
import android.media.MediaRecorder;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
|
||||
public class OrchestraInterfaceInput implements Runnable, OrchestraConstants {
|
||||
private Thread m_thread = null;
|
||||
private int m_uid = -1;
|
||||
private OrchestraNative m_orchestraNativeHandle;
|
||||
private boolean m_stop = false;
|
||||
private boolean m_suspend = false;
|
||||
private AudioRecord m_audio = null;
|
||||
private int m_sampleRate = 48000;
|
||||
private int m_nbChannel = 2;
|
||||
private int m_format = 1;
|
||||
private int m_bufferSize = BUFFER_SIZE;
|
||||
|
||||
public OrchestraInterfaceInput(int _id, OrchestraNative _instance, int _idDevice, int _sampleRate, int _nbChannel, int _format) {
|
||||
Log.d("InterfaceInput", "new: Input");
|
||||
m_uid = _id;
|
||||
m_orchestraNativeHandle = _instance;
|
||||
m_stop = false;
|
||||
m_suspend = false;
|
||||
m_sampleRate = _sampleRate;
|
||||
m_nbChannel = _nbChannel;
|
||||
m_format = _format;
|
||||
m_bufferSize = BUFFER_SIZE * m_nbChannel;
|
||||
}
|
||||
public int getUId() {
|
||||
return m_uid;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Log.e("InterfaceInput", "RUN (start)");
|
||||
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
|
||||
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
|
||||
// we keep the minimum buffer size, otherwite the delay is too big ...
|
||||
// TODO : int bufferSize = AudioRecord.getMinBufferSize(m_sampleRate, channelConfig, audioFormat);
|
||||
int config = 0;
|
||||
if (m_nbChannel == 1) {
|
||||
config = AudioFormat.CHANNEL_IN_MONO;
|
||||
} else {
|
||||
config = AudioFormat.CHANNEL_IN_STEREO;
|
||||
}
|
||||
// Create a streaming AudioTrack for music playback
|
||||
short[] streamBuffer = new short[m_bufferSize];
|
||||
m_audio = new AudioRecord(MediaRecorder.AudioSource.MIC,
|
||||
m_sampleRate,
|
||||
config,
|
||||
audioFormat,
|
||||
m_bufferSize);
|
||||
m_audio.startRecording();
|
||||
|
||||
while ( m_stop == false
|
||||
&& m_suspend == false) {
|
||||
// Stream PCM data into the local buffer
|
||||
m_audio.read(streamBuffer, 0, m_bufferSize);
|
||||
// Send it to C++
|
||||
m_orchestraNativeHandle.record(m_uid, streamBuffer, m_bufferSize/m_nbChannel);
|
||||
}
|
||||
m_audio.stop();
|
||||
m_audio = null;
|
||||
streamBuffer = null;
|
||||
Log.e("InterfaceInput", "RUN (stop)");
|
||||
}
|
||||
|
||||
public void autoStart() {
|
||||
m_stop=false;
|
||||
if (m_suspend == false) {
|
||||
Log.e("InterfaceInput", "Create thread");
|
||||
m_thread = new Thread(this);
|
||||
Log.e("InterfaceInput", "start thread");
|
||||
m_thread.start();
|
||||
Log.e("InterfaceInput", "start thread (done)");
|
||||
}
|
||||
}
|
||||
|
||||
public void autoStop() {
|
||||
if(m_audio == null) {
|
||||
return;
|
||||
}
|
||||
m_stop=true;
|
||||
m_thread = null;
|
||||
/*
|
||||
try {
|
||||
super.join();
|
||||
} catch(InterruptedException e) { }
|
||||
*/
|
||||
}
|
||||
public void activityResume() {
|
||||
m_suspend = false;
|
||||
if (m_stop == false) {
|
||||
Log.i("InterfaceInput", "Resume audio stream : " + m_uid);
|
||||
m_thread = new Thread(this);
|
||||
m_thread.start();
|
||||
}
|
||||
}
|
||||
public void activityPause() {
|
||||
if(m_audio == null) {
|
||||
return;
|
||||
}
|
||||
m_suspend = true;
|
||||
Log.i("InterfaceInput", "Pause audio stream : " + m_uid);
|
||||
m_thread = null;
|
||||
}
|
||||
}
|
108
android/org/musicdsp/orchestra/OrchestraInterfaceOutput.java
Normal file
108
android/org/musicdsp/orchestra/OrchestraInterfaceOutput.java
Normal file
@ -0,0 +1,108 @@
|
||||
/**
|
||||
* @author Edouard DUPIN, Kevin BILLONNEAU
|
||||
*
|
||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||
*
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
package org.musicdsp.orchestra;
|
||||
|
||||
import android.media.AudioTrack;
|
||||
import android.media.AudioFormat;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioRecord;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
public class OrchestraInterfaceOutput extends Thread implements OrchestraConstants {
|
||||
private int m_uid = -1;
|
||||
private OrchestraNative m_orchestraNativeHandle;
|
||||
private boolean m_stop = false;
|
||||
private boolean m_suspend = false;
|
||||
private AudioTrack m_audio = null;
|
||||
private int m_sampleRate = 48000;
|
||||
private int m_nbChannel = 2;
|
||||
private int m_format = 1;
|
||||
private int m_bufferSize = BUFFER_SIZE;
|
||||
|
||||
public OrchestraInterfaceOutput(int _id, OrchestraNative _instance, int _idDevice, int _sampleRate, int _nbChannel, int _format) {
|
||||
Log.d("InterfaceOutput", "new: output");
|
||||
m_uid = _id;
|
||||
m_orchestraNativeHandle = _instance;
|
||||
m_stop = true;
|
||||
m_sampleRate = _sampleRate;
|
||||
m_nbChannel = _nbChannel;
|
||||
m_format = _format;
|
||||
m_bufferSize = BUFFER_SIZE * m_nbChannel;
|
||||
}
|
||||
public int getUId() {
|
||||
return m_uid;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Log.e("InterfaceOutput", "RUN (start)");
|
||||
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_STEREO;
|
||||
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
|
||||
// we keep the minimum buffer size, otherwite the delay is too big ...
|
||||
//int bufferSize = AudioTrack.getMinBufferSize(m_sampleRate, channelConfig, audioFormat);
|
||||
int config = 0;
|
||||
if (m_nbChannel == 1) {
|
||||
config = AudioFormat.CHANNEL_OUT_MONO;
|
||||
} else if (m_nbChannel == 4) {
|
||||
config = AudioFormat.CHANNEL_OUT_QUAD;
|
||||
} else {
|
||||
config = AudioFormat.CHANNEL_OUT_STEREO;
|
||||
}
|
||||
// Create a streaming AudioTrack for music playback
|
||||
short[] streamBuffer = new short[m_bufferSize];
|
||||
m_audio = new AudioTrack(AudioManager.STREAM_MUSIC,
|
||||
m_sampleRate,
|
||||
config,
|
||||
audioFormat,
|
||||
m_bufferSize,
|
||||
AudioTrack.MODE_STREAM);
|
||||
m_audio.play();
|
||||
//m_audio.setPositionNotificationPeriod(2048);
|
||||
|
||||
while (m_stop == false) {
|
||||
// Fill buffer with PCM data from C++
|
||||
m_orchestraNativeHandle.playback(m_uid, streamBuffer, m_bufferSize/m_nbChannel);
|
||||
// Stream PCM data into the music AudioTrack
|
||||
m_audio.write(streamBuffer, 0, m_bufferSize);
|
||||
}
|
||||
|
||||
m_audio.flush();
|
||||
m_audio.stop();
|
||||
m_audio = null;
|
||||
streamBuffer = null;
|
||||
Log.e("InterfaceOutput", "RUN (stop)");
|
||||
}
|
||||
public void autoStart() {
|
||||
m_stop=false;
|
||||
this.start();
|
||||
}
|
||||
public void autoStop() {
|
||||
if(m_audio == null) {
|
||||
return;
|
||||
}
|
||||
m_stop=true;
|
||||
try {
|
||||
super.join();
|
||||
} catch(InterruptedException e) { }
|
||||
}
|
||||
public void activityResume() {
|
||||
if (m_audio != null) {
|
||||
Log.i("InterfaceOutput", "Resume audio stream : " + m_uid);
|
||||
m_audio.play();
|
||||
}
|
||||
}
|
||||
public void activityPause() {
|
||||
if(m_audio == null) {
|
||||
return;
|
||||
}
|
||||
if (m_audio != null) {
|
||||
Log.i("InterfaceOutput", "Pause audio stream : " + m_uid);
|
||||
m_audio.pause();
|
||||
}
|
||||
}
|
||||
}
|
262
android/org/musicdsp/orchestra/OrchestraManager.java
Normal file
262
android/org/musicdsp/orchestra/OrchestraManager.java
Normal file
@ -0,0 +1,262 @@
|
||||
/**
|
||||
* @author Edouard DUPIN
|
||||
*
|
||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||
*
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
package org.musicdsp.orchestra;
|
||||
|
||||
import android.util.Log;
|
||||
import java.util.Vector;
|
||||
|
||||
//import org.musicdsp.orchestra.Constants;
|
||||
//import org.musicdsp.orchestra.ManagerCallback;
|
||||
//import org.musicdsp.orchestra.Orchestra;
|
||||
//import org.musicdsp.orchestra.InterfaceOutput;
|
||||
//import org.musicdsp.orchestra.InterfaceInput;
|
||||
|
||||
/**
|
||||
* @brief Class :
|
||||
*
|
||||
*/
|
||||
public class OrchestraManager implements OrchestraManagerCallback, OrchestraConstants {
|
||||
private OrchestraNative m_orchestraHandle;
|
||||
private int m_uid = 0;
|
||||
private Vector<OrchestraInterfaceOutput> m_outputList;
|
||||
private Vector<OrchestraInterfaceInput> m_inputList;
|
||||
|
||||
public OrchestraManager() {
|
||||
// set the java evironement in the C sources :
|
||||
m_orchestraHandle = new OrchestraNative(this);
|
||||
m_outputList = new Vector<OrchestraInterfaceOutput>();
|
||||
m_inputList = new Vector<OrchestraInterfaceInput>();
|
||||
}
|
||||
|
||||
public int getDeviceCount() {
|
||||
Log.e("Manager", "Get device List");
|
||||
return 2;
|
||||
}
|
||||
|
||||
public String getDeviceProperty(int _idDevice) {
|
||||
if (_idDevice == 0) {
|
||||
return "{\n"
|
||||
+ " name:'speaker',\n"
|
||||
+ " type:'output',\n"
|
||||
+ " sample-rate:[8000,16000,24000,32000,48000,96000],\n"
|
||||
+ " channels:['front-left','front-right'],\n"
|
||||
+ " format:['int16'],\n"
|
||||
+ " default:true\n"
|
||||
+ "}";
|
||||
} else if (_idDevice == 1) {
|
||||
return "{\n"
|
||||
+ " name:'microphone',\n"
|
||||
+ " type:'input',\n"
|
||||
+ " sample-rate:[8000,16000,24000,32000,48000,96000],\n"
|
||||
+ " channels:['front-left','front-right'],\n"
|
||||
+ " format:['int16'],\n"
|
||||
+ " default:true\n"
|
||||
+ "}";
|
||||
} else {
|
||||
return "{}";
|
||||
}
|
||||
}
|
||||
|
||||
public int openDeviceOutput(int _idDevice, int _freq, int _nbChannel, int _format) {
|
||||
OrchestraInterfaceOutput iface = new OrchestraInterfaceOutput(m_uid, m_orchestraHandle, _idDevice, _freq, _nbChannel, _format);
|
||||
m_uid++;
|
||||
Log.e("Manager", "Open device Output: " + _idDevice + " with m_uid=" + (m_uid-1));
|
||||
if (iface != null) {
|
||||
m_outputList.add(iface);
|
||||
Log.e("Manager", "Added element count=" + m_outputList.size());
|
||||
return m_uid-1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public int openDeviceInput(int _idDevice, int _freq, int _nbChannel, int _format) {
|
||||
OrchestraInterfaceInput iface = new OrchestraInterfaceInput(m_uid, m_orchestraHandle, _idDevice, _freq, _nbChannel, _format);
|
||||
m_uid++;
|
||||
Log.e("Manager", "Open device Input: " + _idDevice + " with m_uid=" + (m_uid-1));
|
||||
if (iface != null) {
|
||||
m_inputList.add(iface);
|
||||
return m_uid-1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public boolean closeDevice(int _uniqueID) {
|
||||
Log.e("Manager", "Close device : " + _uniqueID);
|
||||
if (_uniqueID<0) {
|
||||
Log.e("Manager", "Can not Close device with m_uid: " + _uniqueID);
|
||||
return false;
|
||||
}
|
||||
// find the Element with his ID:
|
||||
if (m_inputList != null) {
|
||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
||||
if (m_inputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
if (m_inputList.get(iii).getUId() == _uniqueID) {
|
||||
// find it ...
|
||||
m_inputList.remove(iii);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_outputList != null) {
|
||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
||||
if (m_outputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
if (m_outputList.get(iii).getUId() == _uniqueID) {
|
||||
// find it ...
|
||||
m_outputList.remove(iii);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.e("Manager", "Can not start device with m_uid: " + _uniqueID + " Element does not exist ...");
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean start(int _uniqueID) {
|
||||
Log.e("Manager", "start device : " + _uniqueID);
|
||||
if (_uniqueID<0) {
|
||||
Log.e("Manager", "Can not start device with m_uid: " + _uniqueID);
|
||||
return false;
|
||||
}
|
||||
// find the Element with his ID:
|
||||
if (m_inputList != null) {
|
||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
||||
if (m_inputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
if (m_inputList.get(iii).getUId() == _uniqueID) {
|
||||
// find it ...
|
||||
m_inputList.get(iii).autoStart();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_outputList != null) {
|
||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
||||
if (m_outputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
if (m_outputList.get(iii).getUId() == _uniqueID) {
|
||||
// find it ...
|
||||
m_outputList.get(iii).autoStart();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.e("Manager", "Can not start device with UID: " + _uniqueID + " Element does not exist ...");
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean stop(int _uniqueID) {
|
||||
Log.e("Manager", "stop device : " + _uniqueID);
|
||||
if (_uniqueID<0) {
|
||||
Log.e("Manager", "Can not stop device with UID: " + _uniqueID);
|
||||
return false;
|
||||
}
|
||||
// find the Element with his ID:
|
||||
if (m_inputList != null) {
|
||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
||||
if (m_inputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
if (m_inputList.get(iii).getUId() == _uniqueID) {
|
||||
// find it ...
|
||||
m_inputList.get(iii).autoStop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_outputList != null) {
|
||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
||||
if (m_outputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
if (m_outputList.get(iii).getUId() == _uniqueID) {
|
||||
// find it ...
|
||||
m_outputList.get(iii).autoStop();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Log.e("Manager", "Can not stop device with UID: " + _uniqueID + " Element does not exist ...");
|
||||
return false;
|
||||
}
|
||||
public void onCreate() {
|
||||
Log.w("Manager", "onCreate ...");
|
||||
// nothing to do ...
|
||||
}
|
||||
public void onStart() {
|
||||
Log.w("Manager", "onStart ...");
|
||||
// nothing to do ...
|
||||
}
|
||||
public void onRestart() {
|
||||
Log.w("Manager", "onRestart ...");
|
||||
// nothing to do ...
|
||||
}
|
||||
public void onResume() {
|
||||
Log.w("Manager", "onResume ...");
|
||||
// find the Element with his ID:
|
||||
if (m_inputList != null) {
|
||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
||||
if (m_inputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
m_inputList.get(iii).activityResume();
|
||||
}
|
||||
}
|
||||
if (m_outputList != null) {
|
||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
||||
if (m_outputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
m_outputList.get(iii).activityResume();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void onPause() {
|
||||
Log.w("Manager", "onPause ...");
|
||||
// find the Element with his ID:
|
||||
if (m_inputList != null) {
|
||||
for (int iii=0; iii<m_inputList.size(); iii++) {
|
||||
if (m_inputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
m_inputList.get(iii).activityPause();
|
||||
}
|
||||
}
|
||||
if (m_outputList != null) {
|
||||
for (int iii=0; iii<m_outputList.size(); iii++) {
|
||||
if (m_outputList.get(iii) == null) {
|
||||
Log.e("Manager", "Null input element: " + iii);
|
||||
continue;
|
||||
}
|
||||
m_outputList.get(iii).activityPause();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void onStop() {
|
||||
Log.w("Manager", "onStop ...");
|
||||
}
|
||||
public void onDestroy() {
|
||||
Log.w("Manager", "onDestroy ...");
|
||||
}
|
||||
}
|
||||
|
19
android/org/musicdsp/orchestra/OrchestraManagerCallback.java
Normal file
19
android/org/musicdsp/orchestra/OrchestraManagerCallback.java
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* @author Edouard DUPIN, Kevin BILLONNEAU
|
||||
*
|
||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||
*
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
package org.musicdsp.orchestra;
|
||||
|
||||
public interface OrchestraManagerCallback {
|
||||
public int getDeviceCount();
|
||||
public String getDeviceProperty(int _idDevice);
|
||||
public int openDeviceInput(int _idDevice, int _sampleRate, int _nbChannel, int _format);
|
||||
public int openDeviceOutput(int _idDevice, int _sampleRate, int _nbChannel, int _format);
|
||||
public boolean closeDevice(int _uniqueID);
|
||||
public boolean start(int _uniqueID);
|
||||
public boolean stop(int _uniqueID);
|
||||
}
|
43
android/org/musicdsp/orchestra/OrchestraNative.java
Normal file
43
android/org/musicdsp/orchestra/OrchestraNative.java
Normal file
@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @author Edouard DUPIN, Kevin BILLONNEAU
|
||||
*
|
||||
* @copyright 2015, Edouard DUPIN, all right reserved
|
||||
*
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
package org.musicdsp.orchestra;
|
||||
|
||||
import java.lang.UnsatisfiedLinkError;
|
||||
import java.lang.RuntimeException;
|
||||
import android.util.Log;
|
||||
|
||||
public class OrchestraNative {
|
||||
public <T extends OrchestraManagerCallback> OrchestraNative(T _managerInstance) {
|
||||
try {
|
||||
NNsetJavaManager(_managerInstance);
|
||||
} catch (java.lang.UnsatisfiedLinkError e) {
|
||||
Log.e("Orchestra", "JNI binding not present ...");
|
||||
throw new RuntimeException("Orchestra binding not present ...");
|
||||
}
|
||||
Log.d("Orchestra", "new ...");
|
||||
}
|
||||
|
||||
public void setManagerRemove() {
|
||||
NNsetJavaManagerRemove();
|
||||
}
|
||||
|
||||
public void playback(int _flowId, short[] _bufferData, int _nbChunk) {
|
||||
NNPlayback(_flowId, _bufferData, _nbChunk);
|
||||
}
|
||||
|
||||
public void record(int _flowId, short[] _bufferData, int _nbChunk) {
|
||||
NNRecord(_flowId, _bufferData, _nbChunk);
|
||||
}
|
||||
|
||||
private native <T extends OrchestraManagerCallback> void NNsetJavaManager(T _managerInstance);
|
||||
private native void NNsetJavaManagerRemove();
|
||||
private native void NNPlayback(int _flowId, short[] _bufferData, int _nbChunk);
|
||||
private native void NNRecord(int _flowId, short[] _bufferData, int _nbChunk);
|
||||
}
|
||||
|
478
audio/orchestra/Api.cpp
Normal file
478
audio/orchestra/Api.cpp
Normal file
@ -0,0 +1,478 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
//#include <etk/types.hpp>
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <etk/types.hpp>
|
||||
|
||||
// Static variable definitions.
|
||||
const etk::Vector<uint32_t>& audio::orchestra::genericSampleRate() {
|
||||
static etk::Vector<uint32_t> list;
|
||||
if (list.size() == 0) {
|
||||
list.pushBack(4000);
|
||||
list.pushBack(5512);
|
||||
list.pushBack(8000);
|
||||
list.pushBack(9600);
|
||||
list.pushBack(11025);
|
||||
list.pushBack(16000);
|
||||
list.pushBack(22050);
|
||||
list.pushBack(32000);
|
||||
list.pushBack(44100);
|
||||
list.pushBack(48000);
|
||||
list.pushBack(64000);
|
||||
list.pushBack(88200);
|
||||
list.pushBack(96000);
|
||||
list.pushBack(128000);
|
||||
list.pushBack(176400);
|
||||
list.pushBack(192000);
|
||||
list.pushBack(256000);
|
||||
}
|
||||
return list;
|
||||
};
|
||||
|
||||
|
||||
audio::orchestra::Api::Api() :
|
||||
m_callback(null),
|
||||
m_deviceBuffer(null) {
|
||||
m_device[0] = 11111;
|
||||
m_device[1] = 11111;
|
||||
m_state = audio::orchestra::state::closed;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
}
|
||||
|
||||
audio::orchestra::Api::~Api() {
|
||||
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Api::startStream() {
|
||||
ATA_VERBOSE("Start Stream");
|
||||
m_startTime = audio::Time::now();
|
||||
m_duration = echrono::microseconds(0);
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Api::openStream(audio::orchestra::StreamParameters* _oParams,
|
||||
audio::orchestra::StreamParameters* _iParams,
|
||||
enum audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
audio::orchestra::AirTAudioCallback _callback,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
if (m_state != audio::orchestra::state::closed) {
|
||||
ATA_ERROR("a stream is already open!");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if ( _oParams != null
|
||||
&& _oParams->nChannels < 1) {
|
||||
ATA_ERROR("a non-null output StreamParameters structure cannot have an nChannels value less than one.");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if ( _iParams != null
|
||||
&& _iParams->nChannels < 1) {
|
||||
ATA_ERROR("a non-null input StreamParameters structure cannot have an nChannels value less than one.");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if ( _oParams == null
|
||||
&& _iParams == null) {
|
||||
ATA_ERROR("input and output StreamParameters structures are both null!");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if (audio::getFormatBytes(_format) == 0) {
|
||||
ATA_ERROR("'format' parameter value is undefined.");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
uint32_t oChannels = 0;
|
||||
if (_oParams != null) {
|
||||
oChannels = _oParams->nChannels;
|
||||
if ( _oParams->deviceId >= nDevices
|
||||
&& _oParams->deviceName == "") {
|
||||
ATA_ERROR("output device parameter value is invalid.");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
}
|
||||
uint32_t iChannels = 0;
|
||||
if (_iParams != null) {
|
||||
iChannels = _iParams->nChannels;
|
||||
if ( _iParams->deviceId >= nDevices
|
||||
&& _iParams->deviceName == "") {
|
||||
ATA_ERROR("input device parameter value is invalid.");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
}
|
||||
clearStreamInfo();
|
||||
bool result;
|
||||
if (oChannels > 0) {
|
||||
if (_oParams->deviceId == -1) {
|
||||
result = openName(_oParams->deviceName,
|
||||
audio::orchestra::mode_output,
|
||||
oChannels,
|
||||
_oParams->firstChannel,
|
||||
_sampleRate,
|
||||
_format,
|
||||
_bufferFrames,
|
||||
_options);
|
||||
} else {
|
||||
result = open(_oParams->deviceId,
|
||||
audio::orchestra::mode_output,
|
||||
oChannels,
|
||||
_oParams->firstChannel,
|
||||
_sampleRate,
|
||||
_format,
|
||||
_bufferFrames,
|
||||
_options);
|
||||
}
|
||||
if (result == false) {
|
||||
ATA_ERROR("system ERROR");
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
}
|
||||
if (iChannels > 0) {
|
||||
if (_iParams->deviceId == -1) {
|
||||
result = openName(_iParams->deviceName,
|
||||
audio::orchestra::mode_input,
|
||||
iChannels,
|
||||
_iParams->firstChannel,
|
||||
_sampleRate,
|
||||
_format,
|
||||
_bufferFrames,
|
||||
_options);
|
||||
} else {
|
||||
result = open(_iParams->deviceId,
|
||||
audio::orchestra::mode_input,
|
||||
iChannels,
|
||||
_iParams->firstChannel,
|
||||
_sampleRate,
|
||||
_format,
|
||||
_bufferFrames,
|
||||
_options);
|
||||
}
|
||||
if (result == false) {
|
||||
if (oChannels > 0) {
|
||||
closeStream();
|
||||
}
|
||||
ATA_ERROR("system error");
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
}
|
||||
m_callback = _callback;
|
||||
//_options.numberOfBuffers = m_nBuffers;
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::Api::getDefaultInputDevice() {
|
||||
// Should be implemented in subclasses if possible.
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::Api::getDefaultOutputDevice() {
|
||||
// Should be implemented in subclasses if possible.
|
||||
return 0;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Api::closeStream() {
|
||||
ATA_VERBOSE("Close Stream");
|
||||
// MUST be implemented in subclasses!
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
bool audio::orchestra::Api::open(uint32_t /*device*/,
|
||||
audio::orchestra::mode /*mode*/,
|
||||
uint32_t /*channels*/,
|
||||
uint32_t /*firstChannel*/,
|
||||
uint32_t /*sampleRate*/,
|
||||
audio::format /*format*/,
|
||||
uint32_t * /*bufferSize*/,
|
||||
const audio::orchestra::StreamOptions& /*options*/) {
|
||||
// MUST be implemented in subclasses!
|
||||
return false;
|
||||
}
|
||||
|
||||
void audio::orchestra::Api::tickStreamTime() {
|
||||
//ATA_WARNING("tick : size=" << m_bufferSize << " rate=" << m_sampleRate << " time=" << audio::Duration((int64_t(m_bufferSize) * int64_t(1000000000)) / int64_t(m_sampleRate)).count());
|
||||
//ATA_WARNING(" one element=" << audio::Duration((int64_t(1000000000)) / int64_t(m_sampleRate)).count());
|
||||
m_duration += audio::Duration((int64_t(m_bufferSize) * int64_t(1000000000)) / int64_t(m_sampleRate));
|
||||
}
|
||||
|
||||
long audio::orchestra::Api::getStreamLatency() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return 0;
|
||||
}
|
||||
long totalLatency = 0;
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
totalLatency = m_latency[0];
|
||||
}
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
totalLatency += m_latency[1];
|
||||
}
|
||||
return totalLatency;
|
||||
}
|
||||
|
||||
audio::Time audio::orchestra::Api::getStreamTime() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::Time();
|
||||
}
|
||||
return m_startTime + m_duration;
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::Api::getStreamSampleRate() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return 0;
|
||||
}
|
||||
return m_sampleRate;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Api::verifyStream() {
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("a stream is not open!");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
void audio::orchestra::Api::clearStreamInfo() {
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state::closed;
|
||||
m_sampleRate = 0;
|
||||
m_bufferSize = 0;
|
||||
m_nBuffers = 0;
|
||||
m_userFormat = audio::format_unknow;
|
||||
m_startTime = audio::Time();
|
||||
m_duration = audio::Duration(0);
|
||||
m_deviceBuffer = null;
|
||||
m_callback = null;
|
||||
for (int32_t iii=0; iii<2; ++iii) {
|
||||
m_device[iii] = 11111;
|
||||
m_doConvertBuffer[iii] = false;
|
||||
m_deviceInterleaved[iii] = true;
|
||||
m_doByteSwap[iii] = false;
|
||||
m_nUserChannels[iii] = 0;
|
||||
m_nDeviceChannels[iii] = 0;
|
||||
m_channelOffset[iii] = 0;
|
||||
m_deviceFormat[iii] = audio::format_unknow;
|
||||
m_latency[iii] = 0;
|
||||
m_userBuffer[iii].clear();
|
||||
m_convertInfo[iii].channels = 0;
|
||||
m_convertInfo[iii].inJump = 0;
|
||||
m_convertInfo[iii].outJump = 0;
|
||||
m_convertInfo[iii].inFormat = audio::format_unknow;
|
||||
m_convertInfo[iii].outFormat = audio::format_unknow;
|
||||
m_convertInfo[iii].inOffset.clear();
|
||||
m_convertInfo[iii].outOffset.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void audio::orchestra::Api::setConvertInfo(audio::orchestra::mode _mode, uint32_t _firstChannel) {
|
||||
int32_t idTable = audio::orchestra::modeToIdTable(_mode);
|
||||
if (_mode == audio::orchestra::mode_input) { // convert device to user buffer
|
||||
m_convertInfo[idTable].inJump = m_nDeviceChannels[1];
|
||||
m_convertInfo[idTable].outJump = m_nUserChannels[1];
|
||||
m_convertInfo[idTable].inFormat = m_deviceFormat[1];
|
||||
m_convertInfo[idTable].outFormat = m_userFormat;
|
||||
} else { // convert user to device buffer
|
||||
m_convertInfo[idTable].inJump = m_nUserChannels[0];
|
||||
m_convertInfo[idTable].outJump = m_nDeviceChannels[0];
|
||||
m_convertInfo[idTable].inFormat = m_userFormat;
|
||||
m_convertInfo[idTable].outFormat = m_deviceFormat[0];
|
||||
}
|
||||
if (m_convertInfo[idTable].inJump < m_convertInfo[idTable].outJump) {
|
||||
m_convertInfo[idTable].channels = m_convertInfo[idTable].inJump;
|
||||
} else {
|
||||
m_convertInfo[idTable].channels = m_convertInfo[idTable].outJump;
|
||||
}
|
||||
// Set up the interleave/deinterleave offsets.
|
||||
if (m_deviceInterleaved[idTable] == false) {
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].inOffset.pushBack(kkk * m_bufferSize);
|
||||
m_convertInfo[idTable].outOffset.pushBack(kkk);
|
||||
m_convertInfo[idTable].inJump = 1;
|
||||
}
|
||||
} else {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].inOffset.pushBack(kkk);
|
||||
m_convertInfo[idTable].outOffset.pushBack(kkk * m_bufferSize);
|
||||
m_convertInfo[idTable].outJump = 1;
|
||||
}
|
||||
}
|
||||
} else { // no (de)interleaving
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].inOffset.pushBack(kkk);
|
||||
m_convertInfo[idTable].outOffset.pushBack(kkk);
|
||||
}
|
||||
}
|
||||
|
||||
// Add channel offset.
|
||||
if (_firstChannel > 0) {
|
||||
if (m_deviceInterleaved[idTable]) {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].outOffset[kkk] += _firstChannel;
|
||||
}
|
||||
} else {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].inOffset[kkk] += _firstChannel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].outOffset[kkk] += (_firstChannel * m_bufferSize);
|
||||
}
|
||||
} else {
|
||||
for (int32_t kkk=0; kkk<m_convertInfo[idTable].channels; ++kkk) {
|
||||
m_convertInfo[idTable].inOffset[kkk] += (_firstChannel * m_bufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void audio::orchestra::Api::convertBuffer(char *_outBuffer, char *_inBuffer, audio::orchestra::ConvertInfo &_info) {
|
||||
// This function does format conversion, input/output channel compensation, and
|
||||
// data interleaving/deinterleaving. 24-bit integers are assumed to occupy
|
||||
// the lower three bytes of a 32-bit integer.
|
||||
|
||||
// Clear our device buffer when in/out duplex device channels are different
|
||||
if ( _outBuffer == m_deviceBuffer
|
||||
&& m_mode == audio::orchestra::mode_duplex
|
||||
&& m_nDeviceChannels[0] < m_nDeviceChannels[1]) {
|
||||
memset(_outBuffer, 0, m_bufferSize * _info.outJump * audio::getFormatBytes(_info.outFormat));
|
||||
}
|
||||
switch (audio::getFormatBytes(_info.outFormat)) {
|
||||
case 1:
|
||||
{
|
||||
uint8_t *out = reinterpret_cast<uint8_t*>(_outBuffer);
|
||||
uint8_t *in = reinterpret_cast<uint8_t*>(_inBuffer);
|
||||
for (size_t iii=0; iii<m_bufferSize; ++iii) {
|
||||
for (size_t jjj=0; jjj<_info.channels; jjj++) {
|
||||
out[_info.outOffset[jjj]] = in[_info.inOffset[jjj]];
|
||||
}
|
||||
in += _info.inJump;
|
||||
out += _info.outJump;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
uint16_t *out = reinterpret_cast<uint16_t*>(_outBuffer);
|
||||
uint16_t *in = reinterpret_cast<uint16_t*>(_inBuffer);
|
||||
for (size_t iii=0; iii<m_bufferSize; ++iii) {
|
||||
for (size_t jjj=0; jjj<_info.channels; jjj++) {
|
||||
out[_info.outOffset[jjj]] = in[_info.inOffset[jjj]];
|
||||
}
|
||||
in += _info.inJump;
|
||||
out += _info.outJump;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
uint32_t *out = reinterpret_cast<uint32_t*>(_outBuffer);
|
||||
uint32_t *in = reinterpret_cast<uint32_t*>(_inBuffer);
|
||||
for (size_t iii=0; iii<m_bufferSize; ++iii) {
|
||||
for (size_t jjj=0; jjj<_info.channels; jjj++) {
|
||||
out[_info.outOffset[jjj]] = in[_info.inOffset[jjj]];
|
||||
}
|
||||
in += _info.inJump;
|
||||
out += _info.outJump;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
uint64_t *out = reinterpret_cast<uint64_t*>(_outBuffer);
|
||||
uint64_t *in = reinterpret_cast<uint64_t*>(_inBuffer);
|
||||
for (size_t iii=0; iii<m_bufferSize; ++iii) {
|
||||
for (size_t jjj=0; jjj<_info.channels; jjj++) {
|
||||
out[_info.outOffset[jjj]] = in[_info.inOffset[jjj]];
|
||||
}
|
||||
in += _info.inJump;
|
||||
out += _info.outJump;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void audio::orchestra::Api::byteSwapBuffer(char *_buffer, uint32_t _samples, audio::format _format) {
|
||||
char val;
|
||||
char *ptr;
|
||||
ptr = _buffer;
|
||||
if (_format == audio::format_int16) {
|
||||
for (uint32_t iii=0; iii<_samples; ++iii) {
|
||||
// Swap 1st and 2nd bytes.
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+1);
|
||||
*(ptr+1) = val;
|
||||
|
||||
// Increment 2 bytes.
|
||||
ptr += 2;
|
||||
}
|
||||
} else if ( _format == audio::format_int32
|
||||
|| _format == audio::format_float) {
|
||||
for (uint32_t iii=0; iii<_samples; ++iii) {
|
||||
// Swap 1st and 4th bytes.
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+3);
|
||||
*(ptr+3) = val;
|
||||
|
||||
// Swap 2nd and 3rd bytes.
|
||||
ptr += 1;
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+1);
|
||||
*(ptr+1) = val;
|
||||
|
||||
// Increment 3 more bytes.
|
||||
ptr += 3;
|
||||
}
|
||||
} else if (_format == audio::format_int24) {
|
||||
for (uint32_t iii=0; iii<_samples; ++iii) {
|
||||
// Swap 1st and 3rd bytes.
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+2);
|
||||
*(ptr+2) = val;
|
||||
|
||||
// Increment 2 more bytes.
|
||||
ptr += 2;
|
||||
}
|
||||
} else if (_format == audio::format_double) {
|
||||
for (uint32_t iii=0; iii<_samples; ++iii) {
|
||||
// Swap 1st and 8th bytes
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+7);
|
||||
*(ptr+7) = val;
|
||||
|
||||
// Swap 2nd and 7th bytes
|
||||
ptr += 1;
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+5);
|
||||
*(ptr+5) = val;
|
||||
|
||||
// Swap 3rd and 6th bytes
|
||||
ptr += 1;
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+3);
|
||||
*(ptr+3) = val;
|
||||
|
||||
// Swap 4th and 5th bytes
|
||||
ptr += 1;
|
||||
val = *(ptr);
|
||||
*(ptr) = *(ptr+1);
|
||||
*(ptr+1) = val;
|
||||
|
||||
// Increment 5 more bytes.
|
||||
ptr += 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
180
audio/orchestra/Api.hpp
Normal file
180
audio/orchestra/Api.hpp
Normal file
@ -0,0 +1,180 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/Stream.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <audio/orchestra/type.hpp>
|
||||
#include <audio/orchestra/state.hpp>
|
||||
#include <audio/orchestra/mode.hpp>
|
||||
#include <audio/Time.hpp>
|
||||
#include <audio/Duration.hpp>
|
||||
#include <ememory/memory.hpp>
|
||||
/**
|
||||
* @brief Audio library namespace
|
||||
*/
|
||||
namespace audio {
|
||||
/**
|
||||
* @brief Audio-orchestra library namespace
|
||||
*/
|
||||
namespace orchestra {
|
||||
const etk::Vector<uint32_t>& genericSampleRate();
|
||||
/**
|
||||
* @brief airtaudio callback function prototype.
|
||||
* @param _inputBuffer For input (or duplex) streams, this buffer will hold _nbChunk of input audio chunk (null if no data).
|
||||
* @param _timeInput Timestamp of the first buffer sample (recording time).
|
||||
* @param _outputBuffer For output (or duplex) streams, the client should write _nbChunk of audio chunk into this buffer (null if no data).
|
||||
* @param _timeOutput Timestamp of the first buffer sample (playing time).
|
||||
* @param _nbChunk The number of chunk of input or output chunk in the buffer (same size).
|
||||
* @param _status List of error that occured in the laps of time.
|
||||
*/
|
||||
typedef etk::Function<int32_t (const void* _inputBuffer,
|
||||
const audio::Time& _timeInput,
|
||||
void* _outputBuffer,
|
||||
const audio::Time& _timeOutput,
|
||||
uint32_t _nbChunk,
|
||||
const etk::Vector<audio::orchestra::status>& _status)> AirTAudioCallback;
|
||||
// A protected structure used for buffer conversion.
|
||||
class ConvertInfo {
|
||||
public:
|
||||
int32_t channels;
|
||||
int32_t inJump;
|
||||
int32_t outJump;
|
||||
enum audio::format inFormat;
|
||||
enum audio::format outFormat;
|
||||
etk::Vector<int> inOffset;
|
||||
etk::Vector<int> outOffset;
|
||||
};
|
||||
|
||||
class Api : public ememory::EnableSharedFromThis<Api>{
|
||||
protected:
|
||||
etk::String m_name;
|
||||
public:
|
||||
Api();
|
||||
virtual ~Api();
|
||||
void setName(const etk::String& _name) {
|
||||
m_name = _name;
|
||||
}
|
||||
virtual const etk::String& getCurrentApi() = 0;
|
||||
virtual uint32_t getDeviceCount() = 0;
|
||||
virtual audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device) = 0;
|
||||
// TODO : Check API ...
|
||||
virtual bool getNamedDeviceInfo(const etk::String& _deviceName, audio::orchestra::DeviceInfo& _info) {
|
||||
return false;
|
||||
}
|
||||
virtual uint32_t getDefaultInputDevice();
|
||||
virtual uint32_t getDefaultOutputDevice();
|
||||
enum audio::orchestra::error openStream(audio::orchestra::StreamParameters* _outputParameters,
|
||||
audio::orchestra::StreamParameters* _inputParameters,
|
||||
audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _nbChunk,
|
||||
audio::orchestra::AirTAudioCallback _callback,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
virtual enum audio::orchestra::error closeStream();
|
||||
virtual enum audio::orchestra::error startStream();
|
||||
virtual enum audio::orchestra::error stopStream() = 0;
|
||||
virtual enum audio::orchestra::error abortStream() = 0;
|
||||
long getStreamLatency();
|
||||
uint32_t getStreamSampleRate();
|
||||
virtual audio::Time getStreamTime();
|
||||
bool isStreamOpen() const {
|
||||
return m_state != audio::orchestra::state::closed;
|
||||
}
|
||||
bool isStreamRunning() const {
|
||||
return m_state == audio::orchestra::state::running;
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable ethread::Mutex m_mutex;
|
||||
audio::orchestra::AirTAudioCallback m_callback;
|
||||
uint32_t m_device[2]; // Playback and record, respectively.
|
||||
enum audio::orchestra::mode m_mode; // audio::orchestra::mode_output, audio::orchestra::mode_input, or audio::orchestra::mode_duplex.
|
||||
enum audio::orchestra::state m_state; // STOPPED, RUNNING, or CLOSED
|
||||
etk::Vector<char> m_userBuffer[2]; // Playback and record, respectively.
|
||||
char *m_deviceBuffer;
|
||||
bool m_doConvertBuffer[2]; // Playback and record, respectively.
|
||||
bool m_deviceInterleaved[2]; // Playback and record, respectively.
|
||||
bool m_doByteSwap[2]; // Playback and record, respectively.
|
||||
uint32_t m_sampleRate; // TODO : Rename frequency
|
||||
uint32_t m_bufferSize;
|
||||
uint32_t m_nBuffers;
|
||||
uint32_t m_nUserChannels[2]; // Playback and record, respectively. // TODO : set only one config (open inout with the same number of channels (limitation)
|
||||
uint32_t m_nDeviceChannels[2]; // Playback and record channels, respectively.
|
||||
uint32_t m_channelOffset[2]; // Playback and record, respectively.
|
||||
uint64_t m_latency[2]; // Playback and record, respectively.
|
||||
enum audio::format m_userFormat; // TODO : Remove this ==> use can only open in the Harware format ...
|
||||
enum audio::format m_deviceFormat[2]; // Playback and record, respectively.
|
||||
audio::orchestra::ConvertInfo m_convertInfo[2];
|
||||
|
||||
//audio::Time
|
||||
audio::Time m_startTime; //!< start time of the stream (restart at every stop, pause ...)
|
||||
audio::Duration m_duration; //!< duration from wich the stream is started
|
||||
|
||||
/**
|
||||
* @brief api-specific method that attempts to open a device
|
||||
* with the given parameters. This function MUST be implemented by
|
||||
* all subclasses. If an error is encountered during the probe, a
|
||||
* "warning" message is reported and false is returned. A
|
||||
* successful probe is indicated by a return value of true.
|
||||
*/
|
||||
virtual bool open(uint32_t _device,
|
||||
enum audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
virtual bool openName(const etk::String& _deviceName,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) { return false; }
|
||||
/**
|
||||
* @brief Increment the stream time.
|
||||
*/
|
||||
void tickStreamTime();
|
||||
/**
|
||||
* @brief Clear an RtApiStream structure.
|
||||
*/
|
||||
void clearStreamInfo();
|
||||
/**
|
||||
* @brief Check the current stream status
|
||||
*/
|
||||
enum audio::orchestra::error verifyStream();
|
||||
/**
|
||||
* @brief Protected method used to perform format, channel number, and/or interleaving
|
||||
* conversions between the user and device buffers.
|
||||
*/
|
||||
void convertBuffer(char *_outBuffer,
|
||||
char *_inBuffer,
|
||||
audio::orchestra::ConvertInfo& _info);
|
||||
|
||||
/**
|
||||
* @brief Perform byte-swapping on buffers.
|
||||
*/
|
||||
void byteSwapBuffer(char *_buffer,
|
||||
uint32_t _samples,
|
||||
enum audio::format _format);
|
||||
/**
|
||||
* @brief Sets up the parameters for buffer conversion.
|
||||
*/
|
||||
void setConvertInfo(enum audio::orchestra::mode _mode,
|
||||
uint32_t _firstChannel);
|
||||
|
||||
public:
|
||||
virtual bool isMasterOf(ememory::SharedPtr<audio::orchestra::Api> _api) {
|
||||
return false;
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
|
0
audio/orchestra/CallbackInfo.hpp
Normal file
0
audio/orchestra/CallbackInfo.hpp
Normal file
61
audio/orchestra/DeviceInfo.cpp
Normal file
61
audio/orchestra/DeviceInfo.cpp
Normal file
@ -0,0 +1,61 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
//#include <etk/types.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <audio/orchestra/DeviceInfo.hpp>
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
void audio::orchestra::DeviceInfo::display(int32_t _tabNumber) const {
|
||||
etk::String space;
|
||||
for (int32_t iii=0; iii<_tabNumber; ++iii) {
|
||||
space += " ";
|
||||
}
|
||||
if (isCorrect == false) {
|
||||
ATA_PRINT(space + "NOT CORRECT INFORAMATIONS");
|
||||
return;
|
||||
}
|
||||
ATA_PRINT(space + "mode=" << (input==true?"input":"output"));
|
||||
ATA_PRINT(space + "name=" << name);
|
||||
if (desc.size() != 0) {
|
||||
ATA_PRINT(space + "desc=" << desc);
|
||||
}
|
||||
ATA_PRINT(space + "channel" << (channels.size()>1?"s":"") << "=" << channels.size() << " : " << channels);
|
||||
ATA_PRINT(space + "rate" << (sampleRates.size()>1?"s":"") << "=" << sampleRates);
|
||||
ATA_PRINT(space + "native Format" << (nativeFormats.size()>1?"s":"") << ": " << nativeFormats);
|
||||
ATA_PRINT(space + "default=" << (isDefault==true?"true":"false"));
|
||||
}
|
||||
|
||||
void audio::orchestra::DeviceInfo::clear() {
|
||||
isCorrect = false;
|
||||
input = false;
|
||||
name = "";
|
||||
desc = "";
|
||||
channels.clear();
|
||||
sampleRates.clear();
|
||||
nativeFormats.clear();
|
||||
isDefault = false;
|
||||
}
|
||||
|
||||
etk::Stream& audio::orchestra::operator <<(etk::Stream& _os, const audio::orchestra::DeviceInfo& _obj) {
|
||||
_os << "{";
|
||||
if (_obj.isCorrect == false) {
|
||||
_os << "NOT CORRECT INFORAMATIONS";
|
||||
} else {
|
||||
_os << "name=" << _obj.name << ", ";
|
||||
if (_obj.desc.size() != 0) {
|
||||
_os << "description=" << _obj.desc << ", ";
|
||||
}
|
||||
_os << "channels=" << _obj.channels << ", ";
|
||||
_os << "default=" << _obj.isDefault << ", ";
|
||||
_os << "rates=" << _obj.sampleRates << ", ";
|
||||
_os << "native Format: " << _obj.nativeFormats;
|
||||
}
|
||||
_os << "}";
|
||||
return _os;
|
||||
}
|
||||
|
49
audio/orchestra/DeviceInfo.hpp
Normal file
49
audio/orchestra/DeviceInfo.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <audio/format.hpp>
|
||||
#include <audio/channel.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
/**
|
||||
* @brief The public device information structure for returning queried values.
|
||||
*/
|
||||
class DeviceInfo {
|
||||
public:
|
||||
bool isCorrect; //!< the information is correct (the system can return information incorect).
|
||||
bool input; //!< true if the device in an input; false: output.
|
||||
etk::String name; //!< Character string device identifier.
|
||||
etk::String desc; //!< description of the device
|
||||
etk::Vector<audio::channel> channels; //!< Channels interfaces.
|
||||
etk::Vector<uint32_t> sampleRates; //!< Supported sample rates (queried from list of standard rates).
|
||||
etk::Vector<audio::format> nativeFormats; //!< Bit mask of supported data formats.
|
||||
bool isDefault; //! is default input/output
|
||||
// Default constructor.
|
||||
DeviceInfo() :
|
||||
isCorrect(false),
|
||||
input(false),
|
||||
name(),
|
||||
desc(),
|
||||
channels(),
|
||||
sampleRates(),
|
||||
nativeFormats(),
|
||||
isDefault(false) {}
|
||||
/**
|
||||
* @brief Display the current information of the device (on console)
|
||||
*/
|
||||
void display(int32_t _tabNumber = 1) const;
|
||||
/**
|
||||
* @brief Clear all internal data
|
||||
*/
|
||||
void clear();
|
||||
};
|
||||
etk::Stream& operator <<(etk::Stream& _os, const audio::orchestra::DeviceInfo& _obj);
|
||||
}
|
||||
}
|
||||
|
9
audio/orchestra/Flags.cpp
Normal file
9
audio/orchestra/Flags.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <audio/orchestra/Flags.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
22
audio/orchestra/Flags.hpp
Normal file
22
audio/orchestra/Flags.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
class Flags {
|
||||
public:
|
||||
bool m_minimizeLatency; // Simple example ==> TODO ...
|
||||
Flags() :
|
||||
m_minimizeLatency(false) {
|
||||
// nothing to do ...
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
186
audio/orchestra/Interface.cpp
Normal file
186
audio/orchestra/Interface.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
//#include <etk/types.hpp>
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <audio/orchestra/api/Alsa.hpp>
|
||||
#include <audio/orchestra/api/Android.hpp>
|
||||
#include <audio/orchestra/api/Asio.hpp>
|
||||
#include <audio/orchestra/api/Core.hpp>
|
||||
#include <audio/orchestra/api/CoreIos.hpp>
|
||||
#include <audio/orchestra/api/Ds.hpp>
|
||||
#include <audio/orchestra/api/Dummy.hpp>
|
||||
#include <audio/orchestra/api/Jack.hpp>
|
||||
#include <audio/orchestra/api/Pulse.hpp>
|
||||
|
||||
etk::Vector<etk::String> audio::orchestra::Interface::getListApi() {
|
||||
etk::Vector<etk::String> apis;
|
||||
// The order here will control the order of RtAudio's API search in
|
||||
// the constructor.
|
||||
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
||||
apis.pushBack(m_apiAvaillable[iii].first);
|
||||
}
|
||||
return apis;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void audio::orchestra::Interface::openApi(const etk::String& _api) {
|
||||
m_api.reset();
|
||||
for (size_t iii=0; iii<m_apiAvaillable.size(); ++iii) {
|
||||
ATA_INFO("try open " << m_apiAvaillable[iii].first);
|
||||
if (_api == m_apiAvaillable[iii].first) {
|
||||
ATA_INFO(" ==> call it");
|
||||
m_api = m_apiAvaillable[iii].second();
|
||||
if (m_api != null) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO : An error occured ...
|
||||
ATA_ERROR("Error in open API ...");
|
||||
}
|
||||
|
||||
|
||||
audio::orchestra::Interface::Interface() :
|
||||
m_api(null) {
|
||||
ATA_DEBUG("Add interface:");
|
||||
#if defined(ORCHESTRA_BUILD_JACK)
|
||||
addInterface(audio::orchestra::typeJack, audio::orchestra::api::Jack::create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_ALSA)
|
||||
addInterface(audio::orchestra::typeAlsa, audio::orchestra::api::Alsa::create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_PULSE)
|
||||
addInterface(audio::orchestra::typePulse, audio::orchestra::api::Pulse::create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_ASIO)
|
||||
addInterface(audio::orchestra::typeAsio, audio::orchestra::api::Asio::create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_DS)
|
||||
addInterface(audio::orchestra::typeDs, audio::orchestra::api::Ds::create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_MACOSX_CORE)
|
||||
addInterface(audio::orchestra::typeCoreOSX, audio::orchestra::api::Core::create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_IOS_CORE)
|
||||
addInterface(audio::orchestra::typeCoreIOS, audio::orchestra::api::CoreIos::create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_JAVA)
|
||||
addInterface(audio::orchestra::typeJava, audio::orchestra::api::Android::create);
|
||||
#endif
|
||||
#if defined(ORCHESTRA_BUILD_DUMMY)
|
||||
addInterface(audio::orchestra::typeDummy, audio::orchestra::api::Dummy::create);
|
||||
#endif
|
||||
}
|
||||
|
||||
void audio::orchestra::Interface::addInterface(const etk::String& _api, ememory::SharedPtr<Api> (*_callbackCreate)()) {
|
||||
m_apiAvaillable.pushBack(etk::Pair<etk::String, ememory::SharedPtr<Api> (*)()>(_api, _callbackCreate));
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Interface::clear() {
|
||||
ATA_INFO("Clear API ...");
|
||||
if (m_api == null) {
|
||||
ATA_WARNING("Interface NOT started!");
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
m_api.reset();
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Interface::instanciate(const etk::String& _api) {
|
||||
ATA_INFO("Instanciate API ...");
|
||||
if (m_api != null) {
|
||||
ATA_WARNING("Interface already started!");
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
if (_api != audio::orchestra::typeUndefined) {
|
||||
ATA_INFO("API specified : " << _api);
|
||||
// Attempt to open the specified API.
|
||||
openApi(_api);
|
||||
if (m_api != null) {
|
||||
if (m_api->getDeviceCount() != 0) {
|
||||
ATA_INFO(" ==> api open");
|
||||
}
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
// No compiled support for specified API value. Issue a debug
|
||||
// warning and continue as if no API was specified.
|
||||
ATA_ERROR("API NOT Supported '" << _api << "' not in " << getListApi());
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
ATA_INFO("Auto choice API :");
|
||||
// Iterate through the compiled APIs and return as soon as we find
|
||||
// one with at least one device or we reach the end of the list.
|
||||
etk::Vector<etk::String> apis = getListApi();
|
||||
ATA_INFO(" find : " << apis.size() << " apis.");
|
||||
for (size_t iii=0; iii<apis.size(); ++iii) {
|
||||
ATA_INFO("try open ...");
|
||||
openApi(apis[iii]);
|
||||
if(m_api == null) {
|
||||
ATA_ERROR(" ==> can not create ...");
|
||||
continue;
|
||||
}
|
||||
if (m_api->getDeviceCount() != 0) {
|
||||
ATA_INFO(" ==> api open");
|
||||
break;
|
||||
} else {
|
||||
ATA_INFO(" ==> Interface exist, but have no devices: " << m_api->getDeviceCount());
|
||||
}
|
||||
}
|
||||
if (m_api != null) {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
ATA_ERROR("API NOT Supported '" << _api << "' not in " << getListApi());
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
|
||||
audio::orchestra::Interface::~Interface() {
|
||||
ATA_INFO("Remove interface");
|
||||
m_api.reset();
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::Interface::openStream(audio::orchestra::StreamParameters* _outputParameters,
|
||||
audio::orchestra::StreamParameters* _inputParameters,
|
||||
audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
audio::orchestra::AirTAudioCallback _callback,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
if (m_api == null) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_api->openStream(_outputParameters,
|
||||
_inputParameters,
|
||||
_format,
|
||||
_sampleRate,
|
||||
_bufferFrames,
|
||||
_callback,
|
||||
_options);
|
||||
}
|
||||
|
||||
bool audio::orchestra::Interface::isMasterOf(audio::orchestra::Interface& _interface) {
|
||||
if (m_api == null) {
|
||||
ATA_ERROR("Current Master API is null ...");
|
||||
return false;
|
||||
}
|
||||
if (_interface.m_api == null) {
|
||||
ATA_ERROR("Current Slave API is null ...");
|
||||
return false;
|
||||
}
|
||||
if (m_api->getCurrentApi() != _interface.m_api->getCurrentApi()) {
|
||||
ATA_ERROR("Can not link 2 Interface with not the same Low level type (?)");//" << _interface.m_adac->getCurrentApi() << " != " << m_adac->getCurrentApi() << ")");
|
||||
return false;
|
||||
}
|
||||
if (m_api->getCurrentApi() != audio::orchestra::typeAlsa) {
|
||||
ATA_ERROR("Link 2 device together work only if the interafec is ?");// << audio::orchestra::type::alsa << " not for " << m_api->getCurrentApi());
|
||||
return false;
|
||||
}
|
||||
return m_api->isMasterOf(_interface.m_api);
|
||||
}
|
||||
|
308
audio/orchestra/Interface.hpp
Normal file
308
audio/orchestra/Interface.hpp
Normal file
@ -0,0 +1,308 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/String.hpp>
|
||||
#include <etk/Vector.hpp>
|
||||
#include <etk/Pair.hpp>
|
||||
#include <audio/orchestra/base.hpp>
|
||||
#include <audio/orchestra/CallbackInfo.hpp>
|
||||
#include <audio/orchestra/Api.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
/**
|
||||
* @brief audio::orchestra::Interface class declaration.
|
||||
*
|
||||
* audio::orchestra::Interface is a "controller" used to select an available audio i/o
|
||||
* interface. It presents a common API for the user to call but all
|
||||
* functionality is implemented by the class RtApi and its
|
||||
* subclasses. RtAudio creates an instance of an RtApi subclass
|
||||
* based on the user's API choice. If no choice is made, RtAudio
|
||||
* attempts to make a "logical" API selection.
|
||||
*/
|
||||
class Interface {
|
||||
protected:
|
||||
etk::Vector<etk::Pair<etk::String, ememory::SharedPtr<Api> (*)()> > m_apiAvaillable;
|
||||
protected:
|
||||
ememory::SharedPtr<audio::orchestra::Api> m_api;
|
||||
public:
|
||||
void setName(const etk::String& _name) {
|
||||
if (m_api == null) {
|
||||
return;
|
||||
}
|
||||
m_api->setName(_name);
|
||||
}
|
||||
/**
|
||||
* @brief Get the list of all availlable API in the system.
|
||||
* @return the list of all APIs
|
||||
*/
|
||||
etk::Vector<etk::String> getListApi();
|
||||
/**
|
||||
* @brief Add an interface of the Possible List.
|
||||
* @param[in] _api Type of the interface.
|
||||
* @param[in] _callbackCreate API creation callback.
|
||||
*/
|
||||
void addInterface(const etk::String& _api, ememory::SharedPtr<Api> (*_callbackCreate)());
|
||||
/**
|
||||
* @brief The class constructor.
|
||||
* @note the creating of the basic instance is done by Instanciate
|
||||
*/
|
||||
Interface();
|
||||
/**
|
||||
* @brief The destructor.
|
||||
*
|
||||
* If a stream is running or open, it will be stopped and closed
|
||||
* automatically.
|
||||
*/
|
||||
virtual ~Interface();
|
||||
/**
|
||||
* @brief Clear the current Interface
|
||||
*/
|
||||
enum audio::orchestra::error clear();
|
||||
/**
|
||||
* @brief Create an interface instance
|
||||
*/
|
||||
enum audio::orchestra::error instanciate(const etk::String& _api = audio::orchestra::typeUndefined);
|
||||
/**
|
||||
* @return the audio API specifier for the current instance of airtaudio.
|
||||
*/
|
||||
const etk::String& getCurrentApi() {
|
||||
if (m_api == null) {
|
||||
return audio::orchestra::typeUndefined;
|
||||
}
|
||||
return m_api->getCurrentApi();
|
||||
}
|
||||
/**
|
||||
* @brief A public function that queries for the number of audio devices available.
|
||||
*
|
||||
* This function performs a system query of available devices each time it
|
||||
* is called, thus supporting devices connected \e after instantiation. If
|
||||
* a system error occurs during processing, a warning will be issued.
|
||||
*/
|
||||
uint32_t getDeviceCount() {
|
||||
if (m_api == null) {
|
||||
return 0;
|
||||
}
|
||||
return m_api->getDeviceCount();
|
||||
}
|
||||
/**
|
||||
* @brief Any device integer between 0 and getDeviceCount() - 1 is valid.
|
||||
* If an invalid argument is provided, an RtError (type = INVALID_USE)
|
||||
* will be thrown. If a device is busy or otherwise unavailable, the
|
||||
* structure member "probed" will have a value of "false" and all
|
||||
* other members are undefined. If the specified device is the
|
||||
* current default input or output device, the corresponding
|
||||
* "isDefault" member will have a value of "true".
|
||||
*
|
||||
* @return An audio::orchestra::DeviceInfo structure for a specified device number.
|
||||
*/
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device) {
|
||||
if (m_api == null) {
|
||||
return audio::orchestra::DeviceInfo();
|
||||
}
|
||||
return m_api->getDeviceInfo(_device);
|
||||
}
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(const etk::String& _deviceName) {
|
||||
if (m_api == null) {
|
||||
return audio::orchestra::DeviceInfo();
|
||||
}
|
||||
audio::orchestra::DeviceInfo info;
|
||||
m_api->getNamedDeviceInfo(_deviceName, info);
|
||||
return info;
|
||||
}
|
||||
/**
|
||||
* @brief A function that returns the index of the default output device.
|
||||
*
|
||||
* If the underlying audio API does not provide a "default
|
||||
* device", or if no devices are available, the return value will be
|
||||
* 0. Note that this is a valid device identifier and it is the
|
||||
* client's responsibility to verify that a device is available
|
||||
* before attempting to open a stream.
|
||||
*/
|
||||
uint32_t getDefaultOutputDevice() {
|
||||
if (m_api == null) {
|
||||
return 0;
|
||||
}
|
||||
return m_api->getDefaultOutputDevice();
|
||||
}
|
||||
/**
|
||||
* @brief A function that returns the index of the default input device.
|
||||
*
|
||||
* If the underlying audio API does not provide a "default
|
||||
* device", or if no devices are available, the return value will be
|
||||
* 0. Note that this is a valid device identifier and it is the
|
||||
* client's responsibility to verify that a device is available
|
||||
* before attempting to open a stream.
|
||||
*/
|
||||
uint32_t getDefaultInputDevice() {
|
||||
if (m_api == null) {
|
||||
return 0;
|
||||
}
|
||||
return m_api->getDefaultInputDevice();
|
||||
}
|
||||
/**
|
||||
* @brief A public function for opening a stream with the specified parameters.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if a stream cannot be
|
||||
* opened with the specified parameters or an error occurs during
|
||||
* processing. An RtError (type = INVALID_USE) is thrown if any
|
||||
* invalid device ID or channel number parameters are specified.
|
||||
* @param _outputParameters Specifies output stream parameters to use
|
||||
* when opening a stream, including a device ID, number of channels,
|
||||
* and starting channel number. For input-only streams, this
|
||||
* argument should be null. The device ID is an index value between
|
||||
* 0 and getDeviceCount() - 1.
|
||||
* @param _inputParameters Specifies input stream parameters to use
|
||||
* when opening a stream, including a device ID, number of channels,
|
||||
* and starting channel number. For output-only streams, this
|
||||
* argument should be null. The device ID is an index value between
|
||||
* 0 and getDeviceCount() - 1.
|
||||
* @param _format An audio::format specifying the desired sample data format.
|
||||
* @param _sampleRate The desired sample rate (sample frames per second).
|
||||
* @param _bufferFrames A pointer to a value indicating the desired
|
||||
* internal buffer size in sample frames. The actual value
|
||||
* used by the device is returned via the same pointer. A
|
||||
* value of zero can be specified, in which case the lowest
|
||||
* allowable value is determined.
|
||||
* @param _callback A client-defined function that will be invoked
|
||||
* when input data is available and/or output data is needed.
|
||||
* @param _options An optional pointer to a structure containing various
|
||||
* global stream options, including a list of OR'ed audio::orchestra::streamFlags
|
||||
* and a suggested number of stream buffers that can be used to
|
||||
* control stream latency. More buffers typically result in more
|
||||
* robust performance, though at a cost of greater latency. If a
|
||||
* value of zero is specified, a system-specific median value is
|
||||
* chosen. If the airtaudio_MINIMIZE_LATENCY flag bit is set, the
|
||||
* lowest allowable value is used. The actual value used is
|
||||
* returned via the structure argument. The parameter is API dependent.
|
||||
* @param _errorCallback A client-defined function that will be invoked
|
||||
* when an error has occured.
|
||||
*/
|
||||
enum audio::orchestra::error openStream(audio::orchestra::StreamParameters *_outputParameters,
|
||||
audio::orchestra::StreamParameters *_inputParameters,
|
||||
enum audio::format _format,
|
||||
uint32_t _sampleRate,
|
||||
uint32_t* _bufferFrames,
|
||||
audio::orchestra::AirTAudioCallback _callback,
|
||||
const audio::orchestra::StreamOptions& _options = audio::orchestra::StreamOptions());
|
||||
|
||||
/**
|
||||
* @brief A function that closes a stream and frees any associated stream memory.
|
||||
*
|
||||
* If a stream is not open, this function issues a warning and
|
||||
* returns (no exception is thrown).
|
||||
*/
|
||||
enum audio::orchestra::error closeStream() {
|
||||
if (m_api == null) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_api->closeStream();
|
||||
}
|
||||
/**
|
||||
* @brief A function that starts a stream.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* running.
|
||||
*/
|
||||
enum audio::orchestra::error startStream() {
|
||||
if (m_api == null) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_api->startStream();
|
||||
}
|
||||
/**
|
||||
* @brief Stop a stream, allowing any samples remaining in the output queue to be played.
|
||||
*
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* stopped.
|
||||
*/
|
||||
enum audio::orchestra::error stopStream() {
|
||||
if (m_api == null) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_api->stopStream();
|
||||
}
|
||||
/**
|
||||
* @brief Stop a stream, discarding any samples remaining in the input/output queue.
|
||||
* An RtError (type = SYSTEM_ERROR) is thrown if an error occurs
|
||||
* during processing. An RtError (type = INVALID_USE) is thrown if a
|
||||
* stream is not open. A warning is issued if the stream is already
|
||||
* stopped.
|
||||
*/
|
||||
enum audio::orchestra::error abortStream() {
|
||||
if (m_api == null) {
|
||||
return audio::orchestra::error_inputNull;
|
||||
}
|
||||
return m_api->abortStream();
|
||||
}
|
||||
/**
|
||||
* @return true if a stream is open and false if not.
|
||||
*/
|
||||
bool isStreamOpen() const {
|
||||
if (m_api == null) {
|
||||
return false;
|
||||
}
|
||||
return m_api->isStreamOpen();
|
||||
}
|
||||
/**
|
||||
* @return true if the stream is running and false if it is stopped or not open.
|
||||
*/
|
||||
bool isStreamRunning() const {
|
||||
if (m_api == null) {
|
||||
return false;
|
||||
}
|
||||
return m_api->isStreamRunning();
|
||||
}
|
||||
/**
|
||||
* @brief If a stream is not open, an RtError (type = INVALID_USE) will be thrown.
|
||||
* @return the number of elapsed seconds since the stream was started.
|
||||
*/
|
||||
audio::Time getStreamTime() {
|
||||
if (m_api == null) {
|
||||
return audio::Time();
|
||||
}
|
||||
return m_api->getStreamTime();
|
||||
}
|
||||
/**
|
||||
* @brief The stream latency refers to delay in audio input and/or output
|
||||
* caused by internal buffering by the audio system and/or hardware.
|
||||
* For duplex streams, the returned value will represent the sum of
|
||||
* the input and output latencies. If a stream is not open, an
|
||||
* RtError (type = INVALID_USE) will be thrown. If the API does not
|
||||
* report latency, the return value will be zero.
|
||||
* @return The internal stream latency in sample frames.
|
||||
*/
|
||||
long getStreamLatency() {
|
||||
if (m_api == null) {
|
||||
return 0;
|
||||
}
|
||||
return m_api->getStreamLatency();
|
||||
}
|
||||
/**
|
||||
* @brief On some systems, the sample rate used may be slightly different
|
||||
* than that specified in the stream parameters. If a stream is not
|
||||
* open, an RtError (type = INVALID_USE) will be thrown.
|
||||
* @return Returns actual sample rate in use by the stream.
|
||||
*/
|
||||
uint32_t getStreamSampleRate() {
|
||||
if (m_api == null) {
|
||||
return 0;
|
||||
}
|
||||
return m_api->getStreamSampleRate();
|
||||
}
|
||||
bool isMasterOf(audio::orchestra::Interface& _interface);
|
||||
protected:
|
||||
void openApi(const etk::String& _api);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
45
audio/orchestra/StreamOptions.cpp
Normal file
45
audio/orchestra/StreamOptions.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <audio/orchestra/StreamOptions.hpp>
|
||||
#include <etk/stdTools.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
|
||||
static const char* listValue[] = {
|
||||
"hardware",
|
||||
"trigered",
|
||||
"soft"
|
||||
};
|
||||
|
||||
etk::Stream& audio::orchestra::operator <<(etk::Stream& _os, enum audio::orchestra::timestampMode _obj) {
|
||||
_os << listValue[_obj];
|
||||
return _os;
|
||||
}
|
||||
|
||||
namespace etk {
|
||||
template <> bool from_string<enum audio::orchestra::timestampMode>(enum audio::orchestra::timestampMode& _variableRet, const etk::String& _value) {
|
||||
if (_value == "hardware") {
|
||||
_variableRet = audio::orchestra::timestampMode_Hardware;
|
||||
return true;
|
||||
}
|
||||
if (_value == "trigered") {
|
||||
_variableRet = audio::orchestra::timestampMode_trigered;
|
||||
return true;
|
||||
}
|
||||
if (_value == "soft") {
|
||||
_variableRet = audio::orchestra::timestampMode_soft;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <enum audio::orchestra::timestampMode> etk::String toString(const enum audio::orchestra::timestampMode& _variable) {
|
||||
return listValue[_variable];
|
||||
}
|
||||
}
|
||||
|
||||
|
35
audio/orchestra/StreamOptions.hpp
Normal file
35
audio/orchestra/StreamOptions.hpp
Normal file
@ -0,0 +1,35 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <audio/orchestra/Flags.hpp>
|
||||
#include <etk/String.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum timestampMode {
|
||||
timestampMode_Hardware, //!< enable harware timestamp
|
||||
timestampMode_trigered, //!< get harware triger time stamp and increment with duration
|
||||
timestampMode_soft, //!< Simulate all timestamp.
|
||||
};
|
||||
etk::Stream& operator <<(etk::Stream& _os, enum audio::orchestra::timestampMode _obj);
|
||||
|
||||
class StreamOptions {
|
||||
public:
|
||||
audio::orchestra::Flags flags; //!< A bit-mask of stream flags
|
||||
uint32_t numberOfBuffers; //!< Number of stream buffers.
|
||||
etk::String streamName; //!< A stream name (currently used only in Jack).
|
||||
enum timestampMode mode; //!< mode of timestamping data...
|
||||
// Default constructor.
|
||||
StreamOptions() :
|
||||
flags(),
|
||||
numberOfBuffers(0),
|
||||
mode(timestampMode_Hardware) {}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
30
audio/orchestra/StreamParameters.hpp
Normal file
30
audio/orchestra/StreamParameters.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
/**
|
||||
* @brief The structure for specifying input or ouput stream parameters.
|
||||
*/
|
||||
class StreamParameters {
|
||||
public:
|
||||
int32_t deviceId; //!< Device index (-1 to getDeviceCount() - 1).
|
||||
etk::String deviceName; //!< name of the device (if deviceId==-1 this must not be == "", and the oposite ...)
|
||||
uint32_t nChannels; //!< Number of channels.
|
||||
uint32_t firstChannel; //!< First channel index on device (default = 0).
|
||||
// Default constructor.
|
||||
StreamParameters() :
|
||||
deviceId(-1),
|
||||
nChannels(0),
|
||||
firstChannel(0) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
1606
audio/orchestra/api/Alsa.cpp
Normal file
1606
audio/orchestra/api/Alsa.cpp
Normal file
File diff suppressed because it is too large
Load Diff
79
audio/orchestra/api/Alsa.hpp
Normal file
79
audio/orchestra/api/Alsa.hpp
Normal file
@ -0,0 +1,79 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef ORCHESTRA_BUILD_ALSA
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class AlsaPrivate;
|
||||
class Alsa: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
Alsa();
|
||||
virtual ~Alsa();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typeAlsa;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
private:
|
||||
bool getNamedDeviceInfoLocal(const etk::String& _deviceName,
|
||||
audio::orchestra::DeviceInfo& _info,
|
||||
int32_t _cardId=-1, // Alsa card ID
|
||||
int32_t _subdevice=-1, // alsa subdevice ID
|
||||
int32_t _localDeviceId=-1,// local ID of device find
|
||||
bool _input=false);
|
||||
public:
|
||||
bool getNamedDeviceInfo(const etk::String& _deviceName, audio::orchestra::DeviceInfo& _info) {
|
||||
return getNamedDeviceInfoLocal(_deviceName, _info);
|
||||
}
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
void callbackEventOneCycleRead();
|
||||
void callbackEventOneCycleWrite();
|
||||
void callbackEventOneCycleMMAPRead();
|
||||
void callbackEventOneCycleMMAPWrite();
|
||||
private:
|
||||
ememory::SharedPtr<AlsaPrivate> m_private;
|
||||
etk::Vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool open(uint32_t _device,
|
||||
enum audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
|
||||
bool openName(const etk::String& _deviceName,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
virtual audio::Time getStreamTime();
|
||||
public:
|
||||
bool isMasterOf(ememory::SharedPtr<audio::orchestra::Api> _api);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
195
audio/orchestra/api/Android.cpp
Normal file
195
audio/orchestra/api/Android.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifdef ORCHESTRA_BUILD_JAVA
|
||||
|
||||
//#include <ewol/context/Context.h>
|
||||
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <audio/orchestra/api/AndroidNativeInterface.hpp>
|
||||
#include <audio/orchestra/api/Android.hpp>
|
||||
extern "C" {
|
||||
#include <limits.h>
|
||||
}
|
||||
|
||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Android::create() {
|
||||
ATA_INFO("Create Android device ... ");
|
||||
return ememory::SharedPtr<audio::orchestra::api::Android>(ETK_NEW(audio::orchestra::api::Android));
|
||||
}
|
||||
|
||||
|
||||
audio::orchestra::api::Android::Android() :
|
||||
m_uid(-1) {
|
||||
ATA_INFO("Create Android interface");
|
||||
}
|
||||
|
||||
audio::orchestra::api::Android::~Android() {
|
||||
ATA_INFO("Destroy Android interface");
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::Android::getDeviceCount() {
|
||||
//ATA_INFO("Get device count:"<< m_devices.size());
|
||||
return audio::orchestra::api::android::getDeviceCount();
|
||||
}
|
||||
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Android::getDeviceInfo(uint32_t _device) {
|
||||
//ATA_INFO("Get device info ...");
|
||||
return audio::orchestra::api::android::getDeviceInfo(_device);
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Android::closeStream() {
|
||||
ATA_INFO("Close Stream");
|
||||
// Can not close the stream now...
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Android::startStream() {
|
||||
ATA_INFO("Start Stream");
|
||||
// TODO : Check return ...
|
||||
audio::orchestra::Api::startStream();
|
||||
// Can not close the stream now...
|
||||
return audio::orchestra::api::android::startStream(m_uid);
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Android::stopStream() {
|
||||
ATA_INFO("Stop stream");
|
||||
// Can not close the stream now...
|
||||
return audio::orchestra::api::android::stopStream(m_uid);
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Android::abortStream() {
|
||||
ATA_INFO("Abort Stream");
|
||||
// Can not close the stream now...
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
|
||||
void audio::orchestra::api::Android::playback(int16_t* _dst, int32_t _nbChunk) {
|
||||
// clear output buffer:
|
||||
if (_dst != null) {
|
||||
memset(_dst, 0, _nbChunk*audio::getFormatBytes(m_deviceFormat[modeToIdTable(m_mode)])*m_nDeviceChannels[modeToIdTable(m_mode)]);
|
||||
}
|
||||
int32_t doStopStream = 0;
|
||||
audio::Time streamTime = getStreamTime();
|
||||
etk::Vector<enum audio::orchestra::status> status;
|
||||
if (m_doConvertBuffer[modeToIdTable(m_mode)] == true) {
|
||||
ATA_VERBOSE("Need playback data " << int32_t(_nbChunk) << " userbuffer size = " << m_userBuffer[audio::orchestra::mode_output].size() << "pointer=" << int64_t(&m_userBuffer[audio::orchestra::mode_output][0]));
|
||||
doStopStream = m_callback(null,
|
||||
audio::Time(),
|
||||
&m_userBuffer[m_mode][0],
|
||||
streamTime,
|
||||
uint32_t(_nbChunk),
|
||||
status);
|
||||
convertBuffer((char*)_dst, (char*)&m_userBuffer[audio::orchestra::mode_output][0], m_convertInfo[audio::orchestra::mode_output]);
|
||||
} else {
|
||||
ATA_VERBOSE("Need playback data " << int32_t(_nbChunk) << " pointer=" << int64_t(_dst));
|
||||
doStopStream = m_callback(null,
|
||||
audio::Time(),
|
||||
_dst,
|
||||
streamTime,
|
||||
uint32_t(_nbChunk),
|
||||
status);
|
||||
|
||||
}
|
||||
if (doStopStream == 2) {
|
||||
abortStream();
|
||||
return;
|
||||
}
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
}
|
||||
|
||||
void audio::orchestra::api::Android::record(int16_t* _dst, int32_t _nbChunk) {
|
||||
int32_t doStopStream = 0;
|
||||
audio::Time streamTime = getStreamTime();
|
||||
etk::Vector<enum audio::orchestra::status> status;
|
||||
if (m_doConvertBuffer[modeToIdTable(m_mode)] == true) {
|
||||
ATA_VERBOSE("Need playback data " << int32_t(_nbChunk) << " userbuffer size = " << m_userBuffer[audio::orchestra::mode_output].size() << "pointer=" << int64_t(&m_userBuffer[audio::orchestra::mode_output][0]));
|
||||
convertBuffer((char*)&m_userBuffer[audio::orchestra::mode_input][0], (char*)_dst, m_convertInfo[audio::orchestra::mode_input]);
|
||||
doStopStream = m_callback(&m_userBuffer[m_mode][0],
|
||||
streamTime,
|
||||
null,
|
||||
audio::Time(),
|
||||
uint32_t(_nbChunk),
|
||||
status);
|
||||
} else {
|
||||
ATA_VERBOSE("Need playback data " << int32_t(_nbChunk) << " pointer=" << int64_t(_dst));
|
||||
doStopStream = m_callback(_dst,
|
||||
streamTime,
|
||||
null,
|
||||
audio::Time(),
|
||||
uint32_t(_nbChunk),
|
||||
status);
|
||||
|
||||
}
|
||||
if (doStopStream == 2) {
|
||||
abortStream();
|
||||
return;
|
||||
}
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
}
|
||||
|
||||
bool audio::orchestra::api::Android::open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
bool ret = false;
|
||||
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
|
||||
m_mode = _mode;
|
||||
m_userFormat = _format;
|
||||
m_nUserChannels[modeToIdTable(m_mode)] = _channels;
|
||||
|
||||
m_uid = audio::orchestra::api::android::open(_device, m_mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options, ememory::staticPointerCast<audio::orchestra::api::Android>(sharedFromThis()));
|
||||
if (m_uid < 0) {
|
||||
ret = false;
|
||||
} else {
|
||||
ret = true;
|
||||
}
|
||||
m_bufferSize = 256;
|
||||
m_sampleRate = _sampleRate;
|
||||
m_doByteSwap[modeToIdTable(m_mode)] = false; // for endienness ...
|
||||
|
||||
// TODO : For now, we write it in hard ==> to bu update later ...
|
||||
m_deviceFormat[modeToIdTable(m_mode)] = audio::format_int16;
|
||||
m_nDeviceChannels[modeToIdTable(m_mode)] = 2;
|
||||
m_deviceInterleaved[modeToIdTable(m_mode)] = true;
|
||||
|
||||
m_doConvertBuffer[modeToIdTable(m_mode)] = false;
|
||||
if (m_userFormat != m_deviceFormat[modeToIdTable(m_mode)]) {
|
||||
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
|
||||
}
|
||||
if (m_nUserChannels[modeToIdTable(m_mode)] < m_nDeviceChannels[modeToIdTable(m_mode)]) {
|
||||
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
|
||||
}
|
||||
if ( m_deviceInterleaved[modeToIdTable(m_mode)] == false
|
||||
&& m_nUserChannels[modeToIdTable(m_mode)] > 1) {
|
||||
m_doConvertBuffer[modeToIdTable(m_mode)] = true;
|
||||
}
|
||||
if (m_doConvertBuffer[modeToIdTable(m_mode)] == true) {
|
||||
// Allocate necessary internal buffers.
|
||||
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(m_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
m_userBuffer[modeToIdTable(m_mode)].resize(bufferBytes);
|
||||
if (m_userBuffer[modeToIdTable(m_mode)].size() == 0) {
|
||||
ATA_ERROR("error allocating user buffer memory.");
|
||||
}
|
||||
setConvertInfo(m_mode, _firstChannel);
|
||||
}
|
||||
ATA_INFO("device format : " << m_deviceFormat[modeToIdTable(m_mode)] << " user format : " << m_userFormat);
|
||||
ATA_INFO("device channels : " << m_nDeviceChannels[modeToIdTable(m_mode)] << " user channels : " << m_nUserChannels[modeToIdTable(m_mode)]);
|
||||
ATA_INFO("do convert buffer : " << m_doConvertBuffer[modeToIdTable(m_mode)]);
|
||||
if (ret == false) {
|
||||
ATA_ERROR("Can not open device.");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
60
audio/orchestra/api/Android.hpp
Normal file
60
audio/orchestra/api/Android.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef ORCHESTRA_BUILD_JAVA
|
||||
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class Android: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
Android();
|
||||
virtual ~Android();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typeJava;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
int32_t m_uid;
|
||||
public:
|
||||
int32_t getUId() {
|
||||
return m_uid;
|
||||
}
|
||||
private:
|
||||
etk::Vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
public:
|
||||
void playback(int16_t* _dst, int32_t _nbChunk);
|
||||
void record(int16_t* _dst, int32_t _nbChunk);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
542
audio/orchestra/api/AndroidNativeInterface.cpp
Normal file
542
audio/orchestra/api/AndroidNativeInterface.cpp
Normal file
@ -0,0 +1,542 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
|
||||
extern "C" {
|
||||
#include <jni.h>
|
||||
#include <pthread.h>
|
||||
}
|
||||
#include <ethread/Mutex.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <audio/orchestra/error.hpp>
|
||||
#include <audio/orchestra/api/AndroidNativeInterface.hpp>
|
||||
#include <audio/orchestra/api/Android.hpp>
|
||||
/* include auto generated file */
|
||||
#include <org_musicdsp_orchestra_OrchestraConstants.h>
|
||||
#include <jvm-basics/jvm-basics.hpp>
|
||||
#include <ememory/memory.hpp>
|
||||
#include <ejson/ejson.hpp>
|
||||
|
||||
class AndroidOrchestraContext {
|
||||
public:
|
||||
// get a resources from the java environement :
|
||||
JNIEnv* m_JavaVirtualMachinePointer; //!< the JVM
|
||||
jclass m_javaClassOrchestra; //!< main activity class (android ...)
|
||||
jclass m_javaClassOrchestraCallback;
|
||||
jobject m_javaObjectOrchestraCallback;
|
||||
jmethodID m_javaMethodOrchestraActivityAudioGetDeviceCount;
|
||||
jmethodID m_javaMethodOrchestraActivityAudioGetDeviceProperty;
|
||||
jmethodID m_javaMethodOrchestraActivityAudioOpenDeviceInput;
|
||||
jmethodID m_javaMethodOrchestraActivityAudioOpenDeviceOutput;
|
||||
jmethodID m_javaMethodOrchestraActivityAudioCloseDevice;
|
||||
jmethodID m_javaMethodOrchestraActivityAudioStart;
|
||||
jmethodID m_javaMethodOrchestraActivityAudioStop;
|
||||
jclass m_javaDefaultClassString; //!< default string class
|
||||
private:
|
||||
bool safeInitMethodID(jmethodID& _mid, jclass& _cls, const char* _name, const char* _sign) {
|
||||
_mid = m_JavaVirtualMachinePointer->GetMethodID(_cls, _name, _sign);
|
||||
if(_mid == null) {
|
||||
ATA_ERROR("C->java : Can't find the method " << _name);
|
||||
/* remove access on the virtual machine : */
|
||||
m_JavaVirtualMachinePointer = null;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool java_attach_current_thread(int *_rstatus) {
|
||||
ATA_DEBUG("C->java : call java");
|
||||
if (jvm_basics::getJavaVM() == null) {
|
||||
ATA_ERROR("C->java : JVM not initialised");
|
||||
m_JavaVirtualMachinePointer = null;
|
||||
return false;
|
||||
}
|
||||
*_rstatus = jvm_basics::getJavaVM()->GetEnv((void **) &m_JavaVirtualMachinePointer, JNI_VERSION_1_6);
|
||||
if (*_rstatus == JNI_EDETACHED) {
|
||||
JavaVMAttachArgs lJavaVMAttachArgs;
|
||||
lJavaVMAttachArgs.version = JNI_VERSION_1_6;
|
||||
lJavaVMAttachArgs.name = "EwolNativeThread";
|
||||
lJavaVMAttachArgs.group = null;
|
||||
int status = jvm_basics::getJavaVM()->AttachCurrentThread(&m_JavaVirtualMachinePointer, &lJavaVMAttachArgs);
|
||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
||||
if (status != JNI_OK) {
|
||||
ATA_ERROR("C->java : AttachCurrentThread failed : " << status);
|
||||
m_JavaVirtualMachinePointer = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void java_detach_current_thread(int _status) {
|
||||
if(_status == JNI_EDETACHED) {
|
||||
jvm_basics::getJavaVM()->DetachCurrentThread();
|
||||
m_JavaVirtualMachinePointer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
AndroidOrchestraContext(JNIEnv* _env, jclass _classBase, jobject _objCallback) :
|
||||
m_JavaVirtualMachinePointer(null),
|
||||
m_javaClassOrchestra(0),
|
||||
m_javaClassOrchestraCallback(0),
|
||||
m_javaObjectOrchestraCallback(0),
|
||||
|
||||
m_javaMethodOrchestraActivityAudioGetDeviceCount(0),
|
||||
m_javaMethodOrchestraActivityAudioGetDeviceProperty(0),
|
||||
m_javaMethodOrchestraActivityAudioOpenDeviceInput(0),
|
||||
m_javaMethodOrchestraActivityAudioOpenDeviceOutput(0),
|
||||
m_javaMethodOrchestraActivityAudioCloseDevice(0),
|
||||
m_javaMethodOrchestraActivityAudioStart(0),
|
||||
m_javaMethodOrchestraActivityAudioStop(0),
|
||||
m_javaDefaultClassString(0) {
|
||||
ATA_DEBUG("*******************************************");
|
||||
ATA_DEBUG("** set JVM Pointer (orchestra) **");
|
||||
ATA_DEBUG("*******************************************");
|
||||
m_JavaVirtualMachinePointer = _env;
|
||||
// get default needed all time elements :
|
||||
if (m_JavaVirtualMachinePointer == null) {
|
||||
ATA_ERROR("C->java: NULLPTR jvm interface");
|
||||
return;
|
||||
}
|
||||
ATA_DEBUG("C->java: try load org/musicdsp/orchestra/OrchestraNative class");
|
||||
m_javaClassOrchestra = m_JavaVirtualMachinePointer->FindClass("org/musicdsp/orchestra/OrchestraNative" );
|
||||
if (m_javaClassOrchestra == 0) {
|
||||
ATA_ERROR("C->java : Can't find org/musicdsp/orchestra/OrchestraNative class");
|
||||
// remove access on the virtual machine :
|
||||
m_JavaVirtualMachinePointer = null;
|
||||
return;
|
||||
}
|
||||
/* The object field extends Activity and implement OrchestraCallback */
|
||||
m_javaClassOrchestraCallback = m_JavaVirtualMachinePointer->GetObjectClass(_objCallback);
|
||||
if(m_javaClassOrchestraCallback == null) {
|
||||
ATA_ERROR("C->java : Can't find org/musicdsp/orchestra/OrchestraManagerCallback class");
|
||||
// remove access on the virtual machine :
|
||||
m_JavaVirtualMachinePointer = null;
|
||||
return;
|
||||
}
|
||||
bool functionCallbackIsMissing = false;
|
||||
bool ret= false;
|
||||
|
||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioGetDeviceCount,
|
||||
m_javaClassOrchestraCallback,
|
||||
"getDeviceCount",
|
||||
"()I");
|
||||
if (ret == false) {
|
||||
jvm_basics::checkExceptionJavaVM(_env);
|
||||
ATA_ERROR("system can not start without function : getDeviceCount");
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
|
||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioGetDeviceProperty,
|
||||
m_javaClassOrchestraCallback,
|
||||
"getDeviceProperty",
|
||||
"(I)Ljava/lang/String;");
|
||||
if (ret == false) {
|
||||
jvm_basics::checkExceptionJavaVM(_env);
|
||||
ATA_ERROR("system can not start without function : getDeviceProperty");
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioOpenDeviceInput,
|
||||
m_javaClassOrchestraCallback,
|
||||
"openDeviceInput",
|
||||
"(IIII)I");
|
||||
if (ret == false) {
|
||||
jvm_basics::checkExceptionJavaVM(_env);
|
||||
ATA_ERROR("system can not start without function : openDeviceInput");
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioOpenDeviceOutput,
|
||||
m_javaClassOrchestraCallback,
|
||||
"openDeviceOutput",
|
||||
"(IIII)I");
|
||||
if (ret == false) {
|
||||
jvm_basics::checkExceptionJavaVM(_env);
|
||||
ATA_ERROR("system can not start without function : openDeviceOutput");
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioCloseDevice,
|
||||
m_javaClassOrchestraCallback,
|
||||
"closeDevice",
|
||||
"(I)Z");
|
||||
if (ret == false) {
|
||||
jvm_basics::checkExceptionJavaVM(_env);
|
||||
ATA_ERROR("system can not start without function : closeDevice");
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioStart,
|
||||
m_javaClassOrchestraCallback,
|
||||
"start",
|
||||
"(I)Z");
|
||||
if (ret == false) {
|
||||
jvm_basics::checkExceptionJavaVM(_env);
|
||||
ATA_ERROR("system can not start without function : start");
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
ret = safeInitMethodID(m_javaMethodOrchestraActivityAudioStop,
|
||||
m_javaClassOrchestraCallback,
|
||||
"stop",
|
||||
"(I)Z");
|
||||
if (ret == false) {
|
||||
jvm_basics::checkExceptionJavaVM(_env);
|
||||
ATA_ERROR("system can not start without function : stop");
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
|
||||
|
||||
m_javaObjectOrchestraCallback = _env->NewGlobalRef(_objCallback);
|
||||
if (m_javaObjectOrchestraCallback == null) {
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
|
||||
m_javaDefaultClassString = m_JavaVirtualMachinePointer->FindClass("java/lang/String" );
|
||||
if (m_javaDefaultClassString == 0) {
|
||||
ATA_ERROR("C->java : Can't find java/lang/String" );
|
||||
// remove access on the virtual machine :
|
||||
m_JavaVirtualMachinePointer = null;
|
||||
functionCallbackIsMissing = true;
|
||||
}
|
||||
if (functionCallbackIsMissing == true) {
|
||||
ATA_CRITICAL(" mission one function ==> system can not work withut it...");
|
||||
}
|
||||
}
|
||||
|
||||
~AndroidOrchestraContext() {
|
||||
// TODO ...
|
||||
}
|
||||
|
||||
void unInit(JNIEnv* _env) {
|
||||
_env->DeleteGlobalRef(m_javaObjectOrchestraCallback);
|
||||
m_javaObjectOrchestraCallback = null;
|
||||
}
|
||||
|
||||
uint32_t getDeviceCount() {
|
||||
// Request the clipBoard :
|
||||
ATA_WARNING("C->java : audio get device count");
|
||||
int status;
|
||||
if(!java_attach_current_thread(&status)) {
|
||||
return 0;
|
||||
}
|
||||
ATA_DEBUG("Call CallIntMethod ...");
|
||||
//Call java ...
|
||||
jint ret = m_JavaVirtualMachinePointer->CallIntMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioGetDeviceCount);
|
||||
// manage execption :
|
||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
||||
java_detach_current_thread(status);
|
||||
ATA_WARNING(" find " << (uint32_t)ret << " IO");
|
||||
return (uint32_t)ret;
|
||||
}
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _idDevice) {
|
||||
audio::orchestra::DeviceInfo info;
|
||||
// Request the clipBoard :
|
||||
ATA_WARNING("C->java : audio get device info " << _idDevice);
|
||||
int status;
|
||||
if(!java_attach_current_thread(&status)) {
|
||||
return info;
|
||||
}
|
||||
//Call java ...
|
||||
jstring returnString = (jstring) m_JavaVirtualMachinePointer->CallObjectMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioGetDeviceProperty, _idDevice);
|
||||
const char *js = m_JavaVirtualMachinePointer->GetStringUTFChars(returnString, null);
|
||||
etk::String retString(js);
|
||||
m_JavaVirtualMachinePointer->ReleaseStringUTFChars(returnString, js);
|
||||
//m_JavaVirtualMachinePointer->DeleteLocalRef(returnString);
|
||||
// manage execption :
|
||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
||||
java_detach_current_thread(status);
|
||||
ATA_WARNING("get device information : " << retString);
|
||||
ejson::Document doc;
|
||||
if (doc.parse(retString) == false) {
|
||||
|
||||
return info;
|
||||
}
|
||||
info.name = doc["name"].toString().get("no-name");
|
||||
if (doc["type"].toString().get("output") == "output") {
|
||||
info.input = false;
|
||||
} else {
|
||||
info.input = true;
|
||||
}
|
||||
ejson::Array list = doc["sample-rate"].toArray();
|
||||
if (list.exist() == true) {
|
||||
for (auto it : list) {
|
||||
info.sampleRates.pushBack(int32_t(it.toNumber().get(48000)));
|
||||
}
|
||||
}
|
||||
list = doc["channels"].toArray();
|
||||
if (list.exist() == true) {
|
||||
for (auto it : list) {
|
||||
info.channels.pushBack(audio::getChannelFromString(it.toString().get("???")));
|
||||
}
|
||||
}
|
||||
list = doc["format"].toArray();
|
||||
if (list.exist() == true) {
|
||||
for (auto it : list) {
|
||||
info.nativeFormats.pushBack(audio::getFormatFromString(it.toString().get("???")));
|
||||
}
|
||||
}
|
||||
info.isDefault = doc["default"].toBoolean().get(false);
|
||||
info.isCorrect = true;
|
||||
return info;
|
||||
}
|
||||
private:
|
||||
etk::Vector<ememory::WeakPtr<audio::orchestra::api::Android> > m_instanceList; // list of connected handle ...
|
||||
//AndroidAudioCallback m_audioCallBack;
|
||||
//void* m_audioCallBackUserData;
|
||||
public:
|
||||
int32_t open(uint32_t _idDevice,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options,
|
||||
ememory::SharedPtr<audio::orchestra::api::Android> _instance) {
|
||||
ATA_DEBUG("C->java : audio open device");
|
||||
int status;
|
||||
if(!java_attach_current_thread(&status)) {
|
||||
return -1;
|
||||
}
|
||||
//Call java ...
|
||||
jint ret = false;
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
ret = m_JavaVirtualMachinePointer->CallIntMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioOpenDeviceOutput, _idDevice, _sampleRate, _channels, /*_format*/ 1);
|
||||
} else {
|
||||
ret = m_JavaVirtualMachinePointer->CallIntMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioOpenDeviceInput, _idDevice, _sampleRate, _channels, /*_format*/ 1);
|
||||
}
|
||||
// manage execption :
|
||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
||||
java_detach_current_thread(status);
|
||||
if (int32_t(ret) >= 0) {
|
||||
m_instanceList.pushBack(_instance);
|
||||
return int32_t(ret);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
public:
|
||||
enum audio::orchestra::error closeStream(int32_t _id) {
|
||||
ATA_DEBUG("C->java : audio close device");
|
||||
int status;
|
||||
if(!java_attach_current_thread(&status)) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
//Call java ...
|
||||
jboolean ret = m_JavaVirtualMachinePointer->CallBooleanMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioCloseDevice, _id);
|
||||
// manage execption :
|
||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
||||
java_detach_current_thread(status);
|
||||
if (bool(ret) == false) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error startStream(int32_t _id) {
|
||||
ATA_DEBUG("C->java : audio start device");
|
||||
int status;
|
||||
if(!java_attach_current_thread(&status)) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
//Call java ...
|
||||
jboolean ret = m_JavaVirtualMachinePointer->CallBooleanMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioStart, _id);
|
||||
// manage execption :
|
||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
||||
java_detach_current_thread(status);
|
||||
if (bool(ret) == false) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
enum audio::orchestra::error stopStream(int32_t _id) {
|
||||
|
||||
ATA_DEBUG("C->java : audio close device");
|
||||
int status;
|
||||
if(!java_attach_current_thread(&status)) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
//Call java ...
|
||||
jboolean ret = m_JavaVirtualMachinePointer->CallBooleanMethod(m_javaObjectOrchestraCallback, m_javaMethodOrchestraActivityAudioStop, _id);
|
||||
// manage execption :
|
||||
jvm_basics::checkExceptionJavaVM(m_JavaVirtualMachinePointer);
|
||||
java_detach_current_thread(status);
|
||||
if (bool(ret) == false) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
enum audio::orchestra::error abortStream(int32_t _id) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
|
||||
void playback(int32_t _id, int16_t* _dst, int32_t _nbChunk) {
|
||||
auto it = m_instanceList.begin();
|
||||
while (it != m_instanceList.end()) {
|
||||
auto elem = it->lock();
|
||||
if (elem == null) {
|
||||
it = m_instanceList.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (elem->getUId() == _id) {
|
||||
elem->playback(_dst, _nbChunk);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
void record(int32_t _id, int16_t* _dst, int32_t _nbChunk) {
|
||||
auto it = m_instanceList.begin();
|
||||
while (it != m_instanceList.end()) {
|
||||
auto elem = it->lock();
|
||||
if (elem == null) {
|
||||
it = m_instanceList.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (elem->getUId() == _id) {
|
||||
elem->record(_dst, _nbChunk);
|
||||
}
|
||||
++it;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static ememory::SharedPtr<AndroidOrchestraContext> s_localContext;
|
||||
static int32_t s_nbContextRequested(0);
|
||||
|
||||
|
||||
uint32_t audio::orchestra::api::android::getDeviceCount() {
|
||||
if (s_localContext == null) {
|
||||
ATA_ERROR("Have no Orchertra API instanciate in JAVA ...");
|
||||
return 0;
|
||||
}
|
||||
return s_localContext->getDeviceCount();
|
||||
}
|
||||
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::android::getDeviceInfo(uint32_t _device) {
|
||||
if (s_localContext == null) {
|
||||
return audio::orchestra::DeviceInfo();
|
||||
}
|
||||
return s_localContext->getDeviceInfo(_device);
|
||||
}
|
||||
|
||||
int32_t audio::orchestra::api::android::open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options,
|
||||
ememory::SharedPtr<audio::orchestra::api::Android> _instance) {
|
||||
if (s_localContext == null) {
|
||||
return -1;
|
||||
}
|
||||
return s_localContext->open(_device, _mode, _channels, _firstChannel, _sampleRate, _format, _bufferSize, _options, _instance);
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::android::closeStream(int32_t _id) {
|
||||
if (s_localContext == null) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
return s_localContext->closeStream(_id);
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::android::startStream(int32_t _id) {
|
||||
if (s_localContext == null) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
return s_localContext->startStream(_id);
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::android::stopStream(int32_t _id) {
|
||||
if (s_localContext == null) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
return s_localContext->stopStream(_id);
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::android::abortStream(int32_t _id) {
|
||||
if (s_localContext == null) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
return s_localContext->abortStream(_id);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
void Java_org_musicdsp_orchestra_OrchestraNative_NNsetJavaManager(JNIEnv* _env,
|
||||
jclass _classBase,
|
||||
jobject _objCallback) {
|
||||
ethread::UniqueLock lock(jvm_basics::getMutexJavaVM());
|
||||
ATA_INFO("*******************************************");
|
||||
ATA_INFO("** Creating Orchestra context **");
|
||||
ATA_INFO("*******************************************");
|
||||
if (s_localContext != null) {
|
||||
s_nbContextRequested++;
|
||||
}
|
||||
s_localContext = ememory::makeShared<AndroidOrchestraContext>(_env, _classBase, _objCallback);
|
||||
if (s_localContext == null) {
|
||||
ATA_ERROR("Can not allocate the orchestra main context instance");
|
||||
return;
|
||||
}
|
||||
s_nbContextRequested++;
|
||||
}
|
||||
|
||||
void Java_org_musicdsp_orchestra_OrchestraNative_NNsetJavaManagerRemove(JNIEnv* _env, jclass _cls) {
|
||||
ethread::UniqueLock lock(jvm_basics::getMutexJavaVM());
|
||||
ATA_INFO("*******************************************");
|
||||
ATA_INFO("** remove Orchestra Pointer **");
|
||||
ATA_INFO("*******************************************");
|
||||
if (s_nbContextRequested == 0) {
|
||||
ATA_ERROR("Request remove orchestra interface from Android, but no more interface availlable");
|
||||
return;
|
||||
}
|
||||
s_nbContextRequested--;
|
||||
if (s_nbContextRequested == 0) {
|
||||
s_localContext.reset();
|
||||
}
|
||||
}
|
||||
void Java_org_musicdsp_orchestra_OrchestraNative_NNPlayback(JNIEnv* _env,
|
||||
void* _reserved,
|
||||
jint _id,
|
||||
jshortArray _location,
|
||||
jint _nbChunk) {
|
||||
ethread::UniqueLock lock(jvm_basics::getMutexJavaVM());
|
||||
if (s_localContext == null) {
|
||||
ATA_ERROR("Call audio with no more Low level interface");
|
||||
return;
|
||||
}
|
||||
// get the short* pointer from the Java array
|
||||
jboolean isCopy;
|
||||
jshort* dst = _env->GetShortArrayElements(_location, &isCopy);
|
||||
if (dst != null) {
|
||||
//ATA_INFO("Need audioData " << int32_t(_nbChunk));
|
||||
s_localContext->playback(int32_t(_id), static_cast<short*>(dst), int32_t(_nbChunk));
|
||||
}
|
||||
// TODO : Understand why it did not work corectly ...
|
||||
//if (isCopy == JNI_TRUE) {
|
||||
// release the short* pointer
|
||||
_env->ReleaseShortArrayElements(_location, dst, 0);
|
||||
//}
|
||||
}
|
||||
void Java_org_musicdsp_orchestra_OrchestraNative_NNRecord(JNIEnv* _env,
|
||||
void* _reserved,
|
||||
jint _id,
|
||||
jshortArray _location,
|
||||
jint _nbChunk) {
|
||||
ethread::UniqueLock lock(jvm_basics::getMutexJavaVM());
|
||||
if (s_localContext == null) {
|
||||
ATA_ERROR("Call audio with no more Low level interface");
|
||||
return;
|
||||
}
|
||||
// get the short* pointer from the Java array
|
||||
jboolean isCopy;
|
||||
jshort* dst = _env->GetShortArrayElements(_location, &isCopy);
|
||||
if (dst != null) {
|
||||
//ATA_INFO("Need audioData " << int32_t(_nbChunk));
|
||||
s_localContext->record(int32_t(_id), static_cast<short*>(dst), int32_t(_nbChunk));
|
||||
}
|
||||
// TODO : Understand why it did not work corectly ...
|
||||
//if (isCopy == JNI_TRUE) {
|
||||
// release the short* pointer
|
||||
_env->ReleaseShortArrayElements(_location, dst, 0);
|
||||
//}
|
||||
}
|
||||
}
|
||||
|
42
audio/orchestra/api/AndroidNativeInterface.hpp
Normal file
42
audio/orchestra/api/AndroidNativeInterface.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef ORCHESTRA_BUILD_JAVA
|
||||
|
||||
#include <audio/orchestra/DeviceInfo.hpp>
|
||||
#include <audio/orchestra/mode.hpp>
|
||||
#include <audio/orchestra/error.hpp>
|
||||
#include <audio/orchestra/StreamOptions.hpp>
|
||||
#include <audio/format.hpp>
|
||||
#include <ememory/memory.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class Android;
|
||||
namespace android {
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
int32_t open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options,
|
||||
ememory::SharedPtr<audio::orchestra::api::Android> _instance);
|
||||
enum audio::orchestra::error closeStream(int32_t _id);
|
||||
enum audio::orchestra::error startStream(int32_t _id);
|
||||
enum audio::orchestra::error stopStream(int32_t _id);
|
||||
enum audio::orchestra::error abortStream(int32_t _id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
921
audio/orchestra/api/Asio.cpp
Normal file
921
audio/orchestra/api/Asio.cpp
Normal file
@ -0,0 +1,921 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
|
||||
#if defined(ORCHESTRA_BUILD_ASIO)
|
||||
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
|
||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Asio::create() {
|
||||
return ememory::SharedPtr<audio::orchestra::api::Asio>(ETK_NEW(audio::orchestra::api::Asio));
|
||||
}
|
||||
|
||||
|
||||
// The ASIO API is designed around a callback scheme, so this
|
||||
// implementation is similar to that used for OS-X CoreAudio and Linux
|
||||
// Jack. The primary constraint with ASIO is that it only allows
|
||||
// access to a single driver at a time. Thus, it is not possible to
|
||||
// have more than one simultaneous RtAudio stream.
|
||||
//
|
||||
// This implementation also requires a number of external ASIO files
|
||||
// and a few global variables. The ASIO callback scheme does not
|
||||
// allow for the passing of user data, so we must create a global
|
||||
// pointer to our callbackInfo structure.
|
||||
//
|
||||
// On unix systems, we make use of a pthread condition variable.
|
||||
// Since there is no equivalent in Windows, I hacked something based
|
||||
// on information found in
|
||||
// http://www.cs.wustl.edu/~schmidt/win32-cv-1.html.
|
||||
|
||||
extern "C" {
|
||||
#include "asiosys.h"
|
||||
#include "asio.h"
|
||||
#include "iasiothiscallresolver.h"
|
||||
#include "asiodrivers.h"
|
||||
#include <math.h>
|
||||
}
|
||||
static AsioDrivers drivers;
|
||||
static ASIOCallbacks asioCallbacks;
|
||||
static ASIODriverInfo driverInfo;
|
||||
static CallbackInfo *asioCallbackInfo;
|
||||
static bool asioXRun;
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class AsioPrivate {
|
||||
public:
|
||||
int32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
ASIOBufferInfo *bufferInfos;
|
||||
HANDLE condition;
|
||||
AsioPrivate() :
|
||||
drainCounter(0),
|
||||
internalDrain(false),
|
||||
bufferInfos(0) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function declarations (definitions at end of section)
|
||||
static const char* getAsioErrorString(ASIOError _result);
|
||||
static void sampleRateChanged(ASIOSampleRate _sRate);
|
||||
static long asioMessages(long _selector, long _value, void* _message, double* _opt);
|
||||
|
||||
audio::orchestra::api::Asio::Asio() :
|
||||
m_private(ETK_NEW(audio::orchestra::api::AsioPrivate)) {
|
||||
// ASIO cannot run on a multi-threaded appartment. You can call
|
||||
// CoInitialize beforehand, but it must be for appartment threading
|
||||
// (in which case, CoInitilialize will return S_FALSE here).
|
||||
m_coInitialized = false;
|
||||
HRESULT hr = CoInitialize(null);
|
||||
if (FAILED(hr)) {
|
||||
ATA_ERROR("requires a single-threaded appartment. Call CoInitializeEx(0,COINIT_APARTMENTTHREADED)");
|
||||
}
|
||||
m_coInitialized = true;
|
||||
drivers.removeCurrentDriver();
|
||||
driverInfo.asioVersion = 2;
|
||||
// See note in DirectSound implementation about GetDesktopWindow().
|
||||
driverInfo.sysRef = GetForegroundWindow();
|
||||
}
|
||||
|
||||
audio::orchestra::api::Asio::~Asio() {
|
||||
if (m_state != audio::orchestra::state::closed) {
|
||||
closeStream();
|
||||
}
|
||||
if (m_coInitialized) {
|
||||
CoUninitialize();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::Asio::getDeviceCount() {
|
||||
return (uint32_t) drivers.asioGetNumDev();
|
||||
}
|
||||
|
||||
rtaudio::DeviceInfo audio::orchestra::api::Asio::getDeviceInfo(uint32_t _device) {
|
||||
rtaudio::DeviceInfo info;
|
||||
info.probed = false;
|
||||
// Get device ID
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
if (nDevices == 0) {
|
||||
ATA_ERROR("no devices found!");
|
||||
return info;
|
||||
}
|
||||
if (_device >= nDevices) {
|
||||
ATA_ERROR("device ID is invalid!");
|
||||
return info;
|
||||
}
|
||||
// If a stream is already open, we cannot probe other devices. Thus, use the saved results.
|
||||
if (m_state != audio::orchestra::state::closed) {
|
||||
if (_device >= m_devices.size()) {
|
||||
ATA_ERROR("device ID was not present before stream was opened.");
|
||||
return info;
|
||||
}
|
||||
return m_devices[ _device ];
|
||||
}
|
||||
char driverName[32];
|
||||
ASIOError result = drivers.asioGetDriverName((int) _device, driverName, 32);
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("unable to get driver name (" << getAsioErrorString(result) << ").");
|
||||
return info;
|
||||
}
|
||||
info.name = driverName;
|
||||
if (!drivers.loadDriver(driverName)) {
|
||||
ATA_ERROR("unable to load driver (" << driverName << ").");
|
||||
return info;
|
||||
}
|
||||
result = ASIOInit(&driverInfo);
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") initializing driver (" << driverName << ").");
|
||||
return info;
|
||||
}
|
||||
// Determine the device channel information.
|
||||
long inputChannels, outputChannels;
|
||||
result = ASIOGetChannels(&inputChannels, &outputChannels);
|
||||
if (result != ASE_OK) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") getting channel count (" << driverName << ").");
|
||||
return info;
|
||||
}
|
||||
info.outputChannels = outputChannels;
|
||||
info.inputChannels = inputChannels;
|
||||
if (info.outputChannels > 0 && info.inputChannels > 0) {
|
||||
info.duplexChannels = (info.outputChannels > info.inputChannels) ? info.inputChannels : info.outputChannels;
|
||||
}
|
||||
// Determine the supported sample rates.
|
||||
info.sampleRates.clear();
|
||||
for (uint32_t i=0; i<MAX_SAMPLE_RATES; i++) {
|
||||
result = ASIOCanSampleRate((ASIOSampleRate) SAMPLE_RATES[i]);
|
||||
if (result == ASE_OK) {
|
||||
info.sampleRates.pushBack(SAMPLE_RATES[i]);
|
||||
}
|
||||
}
|
||||
// Determine supported data types ... just check first channel and assume rest are the same.
|
||||
ASIOChannelInfo channelInfo;
|
||||
channelInfo.channel = 0;
|
||||
channelInfo.isInput = true;
|
||||
if (info.inputChannels <= 0) {
|
||||
channelInfo.isInput = false;
|
||||
}
|
||||
result = ASIOGetChannelInfo(&channelInfo);
|
||||
if (result != ASE_OK) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") getting driver channel info (" << driverName << ").");
|
||||
return info;
|
||||
}
|
||||
info.nativeFormats.clear();
|
||||
if ( channelInfo.type == ASIOSTInt16MSB
|
||||
|| channelInfo.type == ASIOSTInt16LSB) {
|
||||
info.nativeFormats.pushBack(audio::format_int16);
|
||||
} else if ( channelInfo.type == ASIOSTInt32MSB
|
||||
|| channelInfo.type == ASIOSTInt32LSB) {
|
||||
info.nativeFormats.pushBack(audio::format_int32);
|
||||
} else if ( channelInfo.type == ASIOSTFloat32MSB
|
||||
|| channelInfo.type == ASIOSTFloat32LSB) {
|
||||
info.nativeFormats.pushBack(audio::format_float);
|
||||
} else if ( channelInfo.type == ASIOSTFloat64MSB
|
||||
|| channelInfo.type == ASIOSTFloat64LSB) {
|
||||
info.nativeFormats.pushBack(audio::format_double);
|
||||
} else if ( channelInfo.type == ASIOSTInt24MSB
|
||||
|| channelInfo.type == ASIOSTInt24LSB) {
|
||||
info.nativeFormats.pushBack(audio::format_int24);
|
||||
}
|
||||
if (info.outputChannels > 0){
|
||||
if (getDefaultOutputDevice() == _device) {
|
||||
info.isDefaultOutput = true;
|
||||
}
|
||||
}
|
||||
if (info.inputChannels > 0) {
|
||||
if (getDefaultInputDevice() == _device) {
|
||||
info.isDefaultInput = true;
|
||||
}
|
||||
}
|
||||
info.probed = true;
|
||||
drivers.removeCurrentDriver();
|
||||
return info;
|
||||
}
|
||||
|
||||
static void bufferSwitch(long _index, ASIOBool _processNow) {
|
||||
RtApiAsio* object = (RtApiAsio*)asioCallbackInfo->object;
|
||||
object->callbackEvent(_index);
|
||||
}
|
||||
|
||||
void audio::orchestra::api::Asio::saveDeviceInfo() {
|
||||
m_devices.clear();
|
||||
uint32_t nDevices = getDeviceCount();
|
||||
m_devices.resize(nDevices);
|
||||
for (uint32_t i=0; i<nDevices; i++) {
|
||||
m_devices[i] = getDeviceInfo(i);
|
||||
}
|
||||
}
|
||||
|
||||
bool audio::orchestra::api::Asio::open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t* _bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
// For ASIO, a duplex stream MUST use the same driver.
|
||||
if ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode == audio::orchestra::mode_output
|
||||
&& m_device[0] != _device) {
|
||||
ATA_ERROR("an ASIO duplex stream must use the same device for input and output!");
|
||||
return false;
|
||||
}
|
||||
char driverName[32];
|
||||
ASIOError result = drivers.asioGetDriverName((int) _device, driverName, 32);
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("unable to get driver name (" << getAsioErrorString(result) << ").");
|
||||
return false;
|
||||
}
|
||||
// Only load the driver once for duplex stream.
|
||||
if ( _mode != audio::orchestra::mode_input
|
||||
|| m_mode != audio::orchestra::mode_output) {
|
||||
// The getDeviceInfo() function will not work when a stream is open
|
||||
// because ASIO does not allow multiple devices to run at the same
|
||||
// time. Thus, we'll probe the system before opening a stream and
|
||||
// save the results for use by getDeviceInfo().
|
||||
this->saveDeviceInfo();
|
||||
if (!drivers.loadDriver(driverName)) {
|
||||
ATA_ERROR("unable to load driver (" << driverName << ").");
|
||||
return false;
|
||||
}
|
||||
result = ASIOInit(&driverInfo);
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") initializing driver (" << driverName << ").");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Check the device channel count.
|
||||
long inputChannels, outputChannels;
|
||||
result = ASIOGetChannels(&inputChannels, &outputChannels);
|
||||
if (result != ASE_OK) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") getting channel count (" << driverName << ").");
|
||||
return false;
|
||||
}
|
||||
if ( ( _mode == audio::orchestra::mode_output
|
||||
&& (_channels+_firstChannel) > (uint32_t) outputChannels)
|
||||
|| ( _mode == audio::orchestra::mode_input
|
||||
&& (_channels+_firstChannel) > (uint32_t) inputChannels)) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("driver (" << driverName << ") does not support requested channel count (" << _channels << ") + offset (" << _firstChannel << ").");
|
||||
return false;
|
||||
}
|
||||
m_nDeviceChannels[modeToIdTable(_mode)] = _channels;
|
||||
m_nUserChannels[modeToIdTable(_mode)] = _channels;
|
||||
m_channelOffset[modeToIdTable(_mode)] = _firstChannel;
|
||||
// Verify the sample rate is supported.
|
||||
result = ASIOCanSampleRate((ASIOSampleRate) _sampleRate);
|
||||
if (result != ASE_OK) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("driver (" << driverName << ") does not support requested sample rate (" << _sampleRate << ").");
|
||||
return false;
|
||||
}
|
||||
// Get the current sample rate
|
||||
ASIOSampleRate currentRate;
|
||||
result = ASIOGetSampleRate(¤tRate);
|
||||
if (result != ASE_OK) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("driver (" << driverName << ") error getting sample rate.");
|
||||
return false;
|
||||
}
|
||||
// Set the sample rate only if necessary
|
||||
if (currentRate != _sampleRate) {
|
||||
result = ASIOSetSampleRate((ASIOSampleRate) _sampleRate);
|
||||
if (result != ASE_OK) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("driver (" << driverName << ") error setting sample rate (" << _sampleRate << ").");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Determine the driver data type.
|
||||
ASIOChannelInfo channelInfo;
|
||||
channelInfo.channel = 0;
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
channelInfo.isInput = false;
|
||||
} else {
|
||||
channelInfo.isInput = true;
|
||||
}
|
||||
result = ASIOGetChannelInfo(&channelInfo);
|
||||
if (result != ASE_OK) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("driver (" << driverName << ") error (" << getAsioErrorString(result) << ") getting data format.");
|
||||
return false;
|
||||
}
|
||||
// Assuming WINDOWS host is always little-endian.
|
||||
m_doByteSwap[modeToIdTable(_mode)] = false;
|
||||
m_userFormat = _format;
|
||||
m_deviceFormat[modeToIdTable(_mode)] = 0;
|
||||
if ( channelInfo.type == ASIOSTInt16MSB
|
||||
|| channelInfo.type == ASIOSTInt16LSB) {
|
||||
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT16;
|
||||
if (channelInfo.type == ASIOSTInt16MSB) {
|
||||
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
} else if ( channelInfo.type == ASIOSTInt32MSB
|
||||
|| channelInfo.type == ASIOSTInt32LSB) {
|
||||
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT32;
|
||||
if (channelInfo.type == ASIOSTInt32MSB) {
|
||||
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
} else if ( channelInfo.type == ASIOSTFloat32MSB
|
||||
|| channelInfo.type == ASIOSTFloat32LSB) {
|
||||
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_FLOAT32;
|
||||
if (channelInfo.type == ASIOSTFloat32MSB) {
|
||||
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
} else if ( channelInfo.type == ASIOSTFloat64MSB
|
||||
|| channelInfo.type == ASIOSTFloat64LSB) {
|
||||
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_FLOAT64;
|
||||
if (channelInfo.type == ASIOSTFloat64MSB) {
|
||||
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
} else if ( channelInfo.type == ASIOSTInt24MSB
|
||||
|| channelInfo.type == ASIOSTInt24LSB) {
|
||||
m_deviceFormat[modeToIdTable(_mode)] = RTAUDIO_SINT24;
|
||||
if (channelInfo.type == ASIOSTInt24MSB) {
|
||||
m_doByteSwap[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
}
|
||||
if (m_deviceFormat[modeToIdTable(_mode)] == 0) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("driver (" << driverName << ") data format not supported by RtAudio.");
|
||||
return false;
|
||||
}
|
||||
// Set the buffer size. For a duplex stream, this will end up
|
||||
// setting the buffer size based on the input constraints, which
|
||||
// should be ok.
|
||||
long minSize, maxSize, preferSize, granularity;
|
||||
result = ASIOGetBufferSize(&minSize, &maxSize, &preferSize, &granularity);
|
||||
if (result != ASE_OK) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("driver (" << driverName << ") error (" << getAsioErrorString(result) << ") getting buffer size.");
|
||||
return false;
|
||||
}
|
||||
if (*_bufferSize < (uint32_t) minSize) {
|
||||
*_bufferSize = (uint32_t) minSize;
|
||||
} else if (*_bufferSize > (uint32_t) maxSize) {
|
||||
*_bufferSize = (uint32_t) maxSize;
|
||||
} else if (granularity == -1) {
|
||||
// Make sure bufferSize is a power of two.
|
||||
int32_t log2_of_min_size = 0;
|
||||
int32_t log2_of_max_size = 0;
|
||||
for (uint32_t i = 0; i < sizeof(long) * 8; i++) {
|
||||
if (minSize & ((long)1 << i)) {
|
||||
log2_of_min_size = i;
|
||||
}
|
||||
if (maxSize & ((long)1 << i)) {
|
||||
log2_of_max_size = i;
|
||||
}
|
||||
}
|
||||
long min_delta = etk::abs((long)*_bufferSize - ((long)1 << log2_of_min_size));
|
||||
int32_t min_delta_num = log2_of_min_size;
|
||||
for (int32_t i = log2_of_min_size + 1; i <= log2_of_max_size; i++) {
|
||||
long current_delta = etk::abs((long)*_bufferSize - ((long)1 << i));
|
||||
if (current_delta < min_delta) {
|
||||
min_delta = current_delta;
|
||||
min_delta_num = i;
|
||||
}
|
||||
}
|
||||
*_bufferSize = ((uint32_t)1 << min_delta_num);
|
||||
if (*_bufferSize < (uint32_t) {
|
||||
minSize) *_bufferSize = (uint32_t) minSize;
|
||||
} else if (*_bufferSize > (uint32_t) maxSize) {
|
||||
*_bufferSize = (uint32_t) maxSize;
|
||||
}
|
||||
} else if (granularity != 0) {
|
||||
// Set to an even multiple of granularity, rounding up.
|
||||
*_bufferSize = (*_bufferSize + granularity-1) / granularity * granularity;
|
||||
}
|
||||
if ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode == audio::orchestra::mode_output
|
||||
&& m_bufferSize != *_bufferSize) {
|
||||
drivers.removeCurrentDriver();
|
||||
ATA_ERROR("input/output buffersize discrepancy!");
|
||||
return false;
|
||||
}
|
||||
m_bufferSize = *_bufferSize;
|
||||
m_nBuffers = 2;
|
||||
// ASIO always uses non-interleaved buffers.
|
||||
m_deviceInterleaved[modeToIdTable(_mode)] = false;
|
||||
m_private->bufferInfos = 0;
|
||||
// Create a manual-reset event.
|
||||
m_private->condition = CreateEvent(null, // no security
|
||||
TRUE, // manual-reset
|
||||
FALSE, // non-signaled initially
|
||||
null); // unnamed
|
||||
// Create the ASIO internal buffers. Since RtAudio sets up input
|
||||
// and output separately, we'll have to dispose of previously
|
||||
// created output buffers for a duplex stream.
|
||||
long inputLatency, outputLatency;
|
||||
if ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode == audio::orchestra::mode_output) {
|
||||
ASIODisposeBuffers();
|
||||
if (m_private->bufferInfos == null) {
|
||||
free(m_private->bufferInfos);
|
||||
m_private->bufferInfos = null;
|
||||
}
|
||||
}
|
||||
// Allocate, initialize, and save the bufferInfos in our stream callbackInfo structure.
|
||||
bool buffersAllocated = false;
|
||||
uint32_t i, nChannels = m_nDeviceChannels[0] + m_nDeviceChannels[1];
|
||||
m_private->bufferInfos = (ASIOBufferInfo *) malloc(nChannels * sizeof(ASIOBufferInfo));
|
||||
if (m_private->bufferInfos == null) {
|
||||
ATA_ERROR("error allocating bufferInfo memory for driver (" << driverName << ").");
|
||||
goto error;
|
||||
}
|
||||
ASIOBufferInfo *infos;
|
||||
infos = m_private->bufferInfos;
|
||||
for (i=0; i<m_nDeviceChannels[0]; i++, infos++) {
|
||||
infos->isInput = ASIOFalse;
|
||||
infos->channelNum = i + m_channelOffset[0];
|
||||
infos->buffers[0] = infos->buffers[1] = 0;
|
||||
}
|
||||
for (i=0; i<m_nDeviceChannels[1]; i++, infos++) {
|
||||
infos->isInput = ASIOTrue;
|
||||
infos->channelNum = i + m_channelOffset[1];
|
||||
infos->buffers[0] = infos->buffers[1] = 0;
|
||||
}
|
||||
// Set up the ASIO callback structure and create the ASIO data buffers.
|
||||
asioCallbacks.bufferSwitch = &bufferSwitch;
|
||||
asioCallbacks.sampleRateDidChange = &sampleRateChanged;
|
||||
asioCallbacks.asioMessage = &asioMessages;
|
||||
asioCallbacks.bufferSwitchTimeInfo = null;
|
||||
result = ASIOCreateBuffers(m_private->bufferInfos, nChannels, m_bufferSize, &asioCallbacks);
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("driver (" << driverName << ") error (" << getAsioErrorString(result) << ") creating buffers.");
|
||||
goto error;
|
||||
}
|
||||
buffersAllocated = true;
|
||||
// Set flags for buffer conversion.
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = false;
|
||||
if (m_userFormat != m_deviceFormat[modeToIdTable(_mode)]) {
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
if ( m_deviceInterleaved[modeToIdTable(_mode)] == false
|
||||
&& m_nUserChannels[modeToIdTable(_mode)] > 1) {
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
// Allocate necessary internal buffers
|
||||
uint64_t bufferBytes;
|
||||
bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * *_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
m_userBuffer[modeToIdTable(_mode)] = (char *) calloc(bufferBytes, 1);
|
||||
if (m_userBuffer[modeToIdTable(_mode)] == null) {
|
||||
ATA_ERROR("error allocating user buffer memory.");
|
||||
goto error;
|
||||
}
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
if (m_mode == audio::orchestra::mode_output && m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes <= bytesOut) {
|
||||
makeBuffer = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (makeBuffer) {
|
||||
bufferBytes *= *_bufferSize;
|
||||
if (m_deviceBuffer) {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = null;
|
||||
}
|
||||
m_deviceBuffer = (char *) calloc(bufferBytes, 1);
|
||||
if (m_deviceBuffer == null) {
|
||||
ATA_ERROR("error allocating device buffer memory.");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_sampleRate = _sampleRate;
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
if ( _mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input) {
|
||||
// We had already set up an output stream.
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
}
|
||||
// Determine device latencies
|
||||
result = ASIOGetLatencies(&inputLatency, &outputLatency);
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("driver (" << driverName << ") error (" << getAsioErrorString(result) << ") getting latency.");
|
||||
} else {
|
||||
m_latency[0] = outputLatency;
|
||||
m_latency[1] = inputLatency;
|
||||
}
|
||||
// Setup the buffer conversion information structure. We don't use
|
||||
// buffers to do channel offsets, so we override that parameter
|
||||
// here.
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
setConvertInfo(_mode, 0);
|
||||
}
|
||||
return true;
|
||||
error:
|
||||
if (buffersAllocated) {
|
||||
ASIODisposeBuffers();
|
||||
}
|
||||
drivers.removeCurrentDriver();
|
||||
CloseHandle(m_private->condition);
|
||||
if (m_private->bufferInfos != null) {
|
||||
free(m_private->bufferInfos);
|
||||
m_private->bufferInfos = null;
|
||||
}
|
||||
for (int32_t i=0; i<2; i++) {
|
||||
if (m_userBuffer[i]) {
|
||||
free(m_userBuffer[i]);
|
||||
m_userBuffer[i] = 0;
|
||||
}
|
||||
}
|
||||
if (m_deviceBuffer) {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Asio::closeStream() {
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::running) {
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
ASIOStop();
|
||||
}
|
||||
ASIODisposeBuffers();
|
||||
drivers.removeCurrentDriver();
|
||||
CloseHandle(m_private->condition);
|
||||
if (m_private->bufferInfos) {
|
||||
free(m_private->bufferInfos);
|
||||
}
|
||||
for (int32_t i=0; i<2; i++) {
|
||||
if (m_userBuffer[i]) {
|
||||
free(m_userBuffer[i]);
|
||||
m_userBuffer[i] = 0;
|
||||
}
|
||||
}
|
||||
if (m_deviceBuffer) {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state::closed;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
bool stopThreadCalled = false;
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Asio::startStream() {
|
||||
// TODO : Check return ...
|
||||
audio::orchestra::Api::startStream();
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
ASIOError result = ASIOStart();
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") starting device.");
|
||||
goto unlock;
|
||||
}
|
||||
m_private->drainCounter = 0;
|
||||
m_private->internalDrain = false;
|
||||
ResetEvent(m_private->condition);
|
||||
m_state = audio::orchestra::state::running;
|
||||
asioXRun = false;
|
||||
unlock:
|
||||
stopThreadCalled = false;
|
||||
if (result == ASE_OK) {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Asio::stopStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if (m_mode == audio::orchestra::mode_output || m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->drainCounter == 0) {
|
||||
m_private->drainCounter = 2;
|
||||
WaitForSingleObject(m_private->condition, INFINITE); // block until signaled
|
||||
}
|
||||
}
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
ASIOError result = ASIOStop();
|
||||
if (result != ASE_OK) {
|
||||
ATA_ERROR("error (" << getAsioErrorString(result) << ") stopping device.");
|
||||
}
|
||||
if (result == ASE_OK) {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Asio::abortStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
error(audio::orchestra::error_warning);
|
||||
return;
|
||||
}
|
||||
|
||||
// The following lines were commented-out because some behavior was
|
||||
// noted where the device buffers need to be zeroed to avoid
|
||||
// continuing sound, even when the device buffers are completely
|
||||
// disposed. So now, calling abort is the same as calling stop.
|
||||
// handle->drainCounter = 2;
|
||||
return stopStream();
|
||||
}
|
||||
|
||||
// This function will be called by a spawned thread when the user
|
||||
// callback function signals that the stream should be stopped or
|
||||
// aborted. It is necessary to handle it this way because the
|
||||
// callbackEvent() function must return before the ASIOStop()
|
||||
// function will return.
|
||||
static unsigned __stdcall asioStopStream(void *_ptr) {
|
||||
CallbackInfo* info = (CallbackInfo*)_ptr;
|
||||
RtApiAsio* object = (RtApiAsio*)info->object;
|
||||
object->stopStream();
|
||||
_endthreadex(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool audio::orchestra::api::Asio::callbackEvent(long bufferIndex) {
|
||||
if ( m_state == audio::orchestra::state::stopped
|
||||
|| m_state == audio::orchestra::state::stopping) {
|
||||
return true;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return false;
|
||||
}
|
||||
CallbackInfo *info = (CallbackInfo *) &m_callbackInfo;
|
||||
// Check if we were draining the stream and signal if finished.
|
||||
if (m_private->drainCounter > 3) {
|
||||
m_state = audio::orchestra::state::stopping;
|
||||
if (m_private->internalDrain == false) {
|
||||
SetEvent(m_private->condition);
|
||||
} else { // spawn a thread to stop the stream
|
||||
unsigned threadId;
|
||||
m_callbackInfo.thread = _beginthreadex(null,
|
||||
0,
|
||||
&asioStopStream,
|
||||
&m_callbackInfo,
|
||||
0,
|
||||
&threadId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Invoke user callback to get fresh output data UNLESS we are
|
||||
// draining stream.
|
||||
if (m_private->drainCounter == 0) {
|
||||
audio::Time streamTime = getStreamTime();
|
||||
etk::Vector<enum audio::orchestra::status status;
|
||||
if (m_mode != audio::orchestra::mode_input && asioXRun == true) {
|
||||
status.pushBack(audio::orchestra::status::underflow);
|
||||
asioXRun = false;
|
||||
}
|
||||
if (m_mode != audio::orchestra::mode_output && asioXRun == true) {
|
||||
status.pushBack(audio::orchestra::status::underflow;
|
||||
asioXRun = false;
|
||||
}
|
||||
int32_t cbReturnValue = info->callback(m_userBuffer[1],
|
||||
streamTime,
|
||||
m_userBuffer[0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = audio::orchestra::state::stopping;
|
||||
m_private->drainCounter = 2;
|
||||
unsigned threadId;
|
||||
m_callbackInfo.thread = _beginthreadex(null,
|
||||
0,
|
||||
&asioStopStream,
|
||||
&m_callbackInfo,
|
||||
0,
|
||||
&threadId);
|
||||
return true;
|
||||
} else if (cbReturnValue == 1) {
|
||||
m_private->drainCounter = 1;
|
||||
m_private->internalDrain = true;
|
||||
}
|
||||
}
|
||||
uint32_t nChannels, bufferBytes, i, j;
|
||||
nChannels = m_nDeviceChannels[0] + m_nDeviceChannels[1];
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
bufferBytes = m_bufferSize * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (m_private->drainCounter > 1) { // write zeros to the output stream
|
||||
for (i=0, j=0; i<nChannels; i++) {
|
||||
if (m_private->bufferInfos[i].isInput != ASIOTrue) {
|
||||
memset(m_private->bufferInfos[i].buffers[bufferIndex], 0, bufferBytes);
|
||||
}
|
||||
}
|
||||
} else if (m_doConvertBuffer[0]) {
|
||||
convertBuffer(m_deviceBuffer, m_userBuffer[0], m_convertInfo[0]);
|
||||
if (m_doByteSwap[0]) {
|
||||
byteSwapBuffer(m_deviceBuffer,
|
||||
m_bufferSize * m_nDeviceChannels[0],
|
||||
m_deviceFormat[0]);
|
||||
}
|
||||
for (i=0, j=0; i<nChannels; i++) {
|
||||
if (m_private->bufferInfos[i].isInput != ASIOTrue) {
|
||||
memcpy(m_private->bufferInfos[i].buffers[bufferIndex],
|
||||
&m_deviceBuffer[j++*bufferBytes],
|
||||
bufferBytes);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (m_doByteSwap[0]) {
|
||||
byteSwapBuffer(m_userBuffer[0],
|
||||
m_bufferSize * m_nUserChannels[0],
|
||||
m_userFormat);
|
||||
}
|
||||
for (i=0, j=0; i<nChannels; i++) {
|
||||
if (m_private->bufferInfos[i].isInput != ASIOTrue) {
|
||||
memcpy(m_private->bufferInfos[i].buffers[bufferIndex],
|
||||
&m_userBuffer[0][bufferBytes*j++],
|
||||
bufferBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_private->drainCounter) {
|
||||
m_private->drainCounter++;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
bufferBytes = m_bufferSize * audio::getFormatBytes(m_deviceFormat[1]);
|
||||
if (m_doConvertBuffer[1]) {
|
||||
// Always interleave ASIO input data.
|
||||
for (i=0, j=0; i<nChannels; i++) {
|
||||
if (m_private->bufferInfos[i].isInput == ASIOTrue) {
|
||||
memcpy(&m_deviceBuffer[j++*bufferBytes],
|
||||
m_private->bufferInfos[i].buffers[bufferIndex],
|
||||
bufferBytes);
|
||||
}
|
||||
}
|
||||
if (m_doByteSwap[1]) {
|
||||
byteSwapBuffer(m_deviceBuffer,
|
||||
m_bufferSize * m_nDeviceChannels[1],
|
||||
m_deviceFormat[1]);
|
||||
}
|
||||
convertBuffer(m_userBuffer[1],
|
||||
m_deviceBuffer,
|
||||
m_convertInfo[1]);
|
||||
} else {
|
||||
for (i=0, j=0; i<nChannels; i++) {
|
||||
if (m_private->bufferInfos[i].isInput == ASIOTrue) {
|
||||
memcpy(&m_userBuffer[1][bufferBytes*j++],
|
||||
m_private->bufferInfos[i].buffers[bufferIndex],
|
||||
bufferBytes);
|
||||
}
|
||||
}
|
||||
if (m_doByteSwap[1]) {
|
||||
byteSwapBuffer(m_userBuffer[1],
|
||||
m_bufferSize * m_nUserChannels[1],
|
||||
m_userFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
// The following call was suggested by Malte Clasen. While the API
|
||||
// documentation indicates it should not be required, some device
|
||||
// drivers apparently do not function correctly without it.
|
||||
ASIOOutputReady();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sampleRateChanged(ASIOSampleRate _sRate) {
|
||||
// The ASIO documentation says that this usually only happens during
|
||||
// external sync. Audio processing is not stopped by the driver,
|
||||
// actual sample rate might not have even changed, maybe only the
|
||||
// sample rate status of an AES/EBU or S/PDIF digital input at the
|
||||
// audio device.
|
||||
RtApi* object = (RtApi*)asioCallbackInfo->object;
|
||||
enum audio::orchestra::error ret = object->stopStream()
|
||||
if (ret != audio::orchestra::error_none) {
|
||||
ATA_ERROR("error stop stream!");
|
||||
} else {
|
||||
ATA_ERROR("driver reports sample rate changed to " << _sRate << " ... stream stopped!!!");
|
||||
}
|
||||
}
|
||||
|
||||
static long asioMessages(long _selector, long _value, void* _message, double* _opt) {
|
||||
long ret = 0;
|
||||
switch(_selector) {
|
||||
case kAsioSelectorSupported:
|
||||
if ( _value == kAsioResetRequest
|
||||
|| _value == kAsioEngineVersion
|
||||
|| _value == kAsioResyncRequest
|
||||
|| _value == kAsioLatenciesChanged
|
||||
// The following three were added for ASIO 2.0, you don't
|
||||
// necessarily have to support them.
|
||||
|| _value == kAsioSupportsTimeInfo
|
||||
|| _value == kAsioSupportsTimeCode
|
||||
|| _value == kAsioSupportsInputMonitor) {
|
||||
ret = 1L;
|
||||
}
|
||||
break;
|
||||
case kAsioResetRequest:
|
||||
// Defer the task and perform the reset of the driver during the
|
||||
// next "safe" situation. You cannot reset the driver right now,
|
||||
// as this code is called from the driver. Reset the driver is
|
||||
// done by completely destruct is. I.e. ASIOStop(),
|
||||
// ASIODisposeBuffers(), Destruction Afterwards you initialize the
|
||||
// driver again.
|
||||
ATA_ERROR("driver reset requested!!!");
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioResyncRequest:
|
||||
// This informs the application that the driver encountered some
|
||||
// non-fatal data loss. It is used for synchronization purposes
|
||||
// of different media. Added mainly to work around the Win16Mutex
|
||||
// problems in Windows 95/98 with the Windows Multimedia system,
|
||||
// which could lose data because the Mutex was held too long by
|
||||
// another thread. However a driver can issue it in other
|
||||
// situations, too.
|
||||
// ATA_ERROR("driver resync requested!!!");
|
||||
asioXRun = true;
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioLatenciesChanged:
|
||||
// This will inform the host application that the drivers were
|
||||
// latencies changed. Beware, it this does not mean that the
|
||||
// buffer sizes have changed! You might need to update internal
|
||||
// delay data.
|
||||
ATA_ERROR("driver latency may have changed!!!");
|
||||
ret = 1L;
|
||||
break;
|
||||
case kAsioEngineVersion:
|
||||
// Return the supported ASIO version of the host application. If
|
||||
// a host application does not implement this selector, ASIO 1.0
|
||||
// is assumed by the driver.
|
||||
ret = 2L;
|
||||
break;
|
||||
case kAsioSupportsTimeInfo:
|
||||
// Informs the driver whether the
|
||||
// asioCallbacks.bufferSwitchTimeInfo() callback is supported.
|
||||
// For compatibility with ASIO 1.0 drivers the host application
|
||||
// should always support the "old" bufferSwitch method, too.
|
||||
ret = 0;
|
||||
break;
|
||||
case kAsioSupportsTimeCode:
|
||||
// Informs the driver whether application is interested in time
|
||||
// code info. If an application does not need to know about time
|
||||
// code, the driver has less work to do.
|
||||
ret = 0;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const char* getAsioErrorString(ASIOError _result) {
|
||||
struct Messages {
|
||||
ASIOError value;
|
||||
const char*message;
|
||||
};
|
||||
static const Messages m[] = {
|
||||
{ ASE_NotPresent, "Hardware input or output is not present or available." },
|
||||
{ ASE_HWMalfunction, "Hardware is malfunctioning." },
|
||||
{ ASE_InvalidParameter, "Invalid input parameter." },
|
||||
{ ASE_InvalidMode, "Invalid mode." },
|
||||
{ ASE_SPNotAdvancing, "Sample position not advancing." },
|
||||
{ ASE_NoClock, "Sample clock or rate cannot be determined or is not present." },
|
||||
{ ASE_NoMemory, "Not enough memory to complete the request." }
|
||||
};
|
||||
for (uint32_t i = 0; i < sizeof(m)/sizeof(m[0]); ++i) {
|
||||
if (m[i].value == result) {
|
||||
return m[i].message;
|
||||
}
|
||||
}
|
||||
return "Unknown error.";
|
||||
}
|
||||
|
||||
#endif
|
53
audio/orchestra/api/Asio.hpp
Normal file
53
audio/orchestra/api/Asio.hpp
Normal file
@ -0,0 +1,53 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef ORCHESTRA_BUILD_ASIO
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class AsioPrivate:
|
||||
class Asio: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
Asio();
|
||||
virtual ~Asio();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typeAsio;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
bool callbackEvent(long _bufferIndex);
|
||||
private:
|
||||
ememory::SharedPtr<AsioPrivate> m_private;
|
||||
etk::Vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool m_coInitialized;
|
||||
bool open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
1300
audio/orchestra/api/Core.cpp
Normal file
1300
audio/orchestra/api/Core.cpp
Normal file
File diff suppressed because it is too large
Load Diff
68
audio/orchestra/api/Core.hpp
Normal file
68
audio/orchestra/api/Core.hpp
Normal file
@ -0,0 +1,68 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef ORCHESTRA_BUILD_MACOSX_CORE
|
||||
|
||||
#include <CoreAudio/AudioHardware.h>
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class CorePrivate;
|
||||
class Core: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
Core();
|
||||
virtual ~Core();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typeCoreOSX;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
uint32_t getDefaultOutputDevice();
|
||||
uint32_t getDefaultInputDevice();
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
long getStreamLatency();
|
||||
bool callbackEvent(AudioDeviceID _deviceId,
|
||||
const AudioBufferList *_inBufferList,
|
||||
const audio::Time& _inTime,
|
||||
const AudioBufferList *_outBufferList,
|
||||
const audio::Time& _outTime);
|
||||
static OSStatus callbackEvent(AudioDeviceID _inDevice,
|
||||
const AudioTimeStamp* _inNow,
|
||||
const AudioBufferList* _inInputData,
|
||||
const AudioTimeStamp* _inInputTime,
|
||||
AudioBufferList* _outOutputData,
|
||||
const AudioTimeStamp* _inOutputTime,
|
||||
void* _infoPointer);
|
||||
static void coreStopStream(void *_userData);
|
||||
private:
|
||||
ememory::SharedPtr<CorePrivate> m_private;
|
||||
bool open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
static const char* getErrorCode(OSStatus _code);
|
||||
static OSStatus xrunListener(AudioObjectID _inDevice,
|
||||
uint32_t _nAddresses,
|
||||
const AudioObjectPropertyAddress _properties[],
|
||||
void* _userData);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
58
audio/orchestra/api/CoreIos.hpp
Normal file
58
audio/orchestra/api/CoreIos.hpp
Normal file
@ -0,0 +1,58 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef ORCHESTRA_BUILD_IOS_CORE
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class CoreIosPrivate;
|
||||
class CoreIos: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
CoreIos();
|
||||
virtual ~CoreIos();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typeCoreIOS;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
etk::Vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
public:
|
||||
void callBackEvent(void* _data,
|
||||
int32_t _nbChunk,
|
||||
const audio::Time& _time);
|
||||
public:
|
||||
ememory::SharedPtr<CoreIosPrivate> m_private;
|
||||
uint32_t getDefaultInputDevice();
|
||||
uint32_t getDefaultOutputDevice();
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
336
audio/orchestra/api/CoreIos.mm
Normal file
336
audio/orchestra/api/CoreIos.mm
Normal file
@ -0,0 +1,336 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#ifdef ORCHESTRA_BUILD_IOS_CORE
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AudioToolbox/AudioToolbox.h>
|
||||
|
||||
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
extern "C" {
|
||||
#include <limits.h>
|
||||
}
|
||||
#include <audio/orchestra/api/CoreIos.hpp>
|
||||
|
||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::CoreIos::create() {
|
||||
ATA_INFO("Create CoreIos device ... ");
|
||||
return ememory::SharedPtr<audio::orchestra::api::CoreIos>(ETK_NEW(audio::orchestra::api::CoreIos));
|
||||
}
|
||||
|
||||
#define kOutputBus 0
|
||||
#define kInputBus 1
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class CoreIosPrivate {
|
||||
public:
|
||||
AudioComponentInstance audioUnit;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
audio::orchestra::api::CoreIos::CoreIos() :
|
||||
m_private(ETK_NEW(audio::orchestra::api::CoreIosPrivate)) {
|
||||
ATA_INFO("new CoreIos");
|
||||
int32_t deviceCount = 2;
|
||||
ATA_ERROR("Get count devices : " << 2);
|
||||
audio::orchestra::DeviceInfo tmp;
|
||||
// Add default output format :
|
||||
tmp.name = "speaker";
|
||||
tmp.input = false;
|
||||
tmp.sampleRates.push_back(48000);
|
||||
tmp.channels.push_back(audio::channel_frontRight);
|
||||
tmp.channels.push_back(audio::channel_frontLeft);
|
||||
tmp.nativeFormats.push_back(audio::format_int16);
|
||||
tmp.isDefault = true;
|
||||
tmp.isCorrect = true;
|
||||
m_devices.push_back(tmp);
|
||||
// add default input format:
|
||||
tmp.name = "microphone";
|
||||
tmp.input = true;
|
||||
tmp.sampleRates.push_back(48000);
|
||||
tmp.channels.push_back(audio::channel_frontRight);
|
||||
tmp.channels.push_back(audio::channel_frontLeft);
|
||||
tmp.nativeFormats.push_back(audio::format_int16);
|
||||
tmp.isDefault = true;
|
||||
tmp.isCorrect = true;
|
||||
m_devices.push_back(tmp);
|
||||
ATA_INFO("Create CoreIOs interface (end)");
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::CoreIos::getDefaultInputDevice() {
|
||||
// Should be implemented in subclasses if possible.
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::CoreIos::getDefaultOutputDevice() {
|
||||
// Should be implemented in subclasses if possible.
|
||||
return 0;
|
||||
}
|
||||
|
||||
audio::orchestra::api::CoreIos::~CoreIos() {
|
||||
ATA_INFO("Destroy CoreIOs interface");
|
||||
AudioUnitUninitialize(m_private->audioUnit);
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::CoreIos::getDeviceCount() {
|
||||
//ATA_INFO("Get device count:"<< m_devices.size());
|
||||
return m_devices.size();
|
||||
}
|
||||
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::CoreIos::getDeviceInfo(uint32_t _device) {
|
||||
//ATA_INFO("Get device info ...");
|
||||
if (_device >= m_devices.size()) {
|
||||
audio::orchestra::DeviceInfo tmp;
|
||||
tmp.sampleRates.push_back(0);
|
||||
tmp.channels.push_back(audio::channel_frontCenter);
|
||||
tmp.isDefault = false;
|
||||
tmp.nativeFormats.push_back(audio::format_int8);
|
||||
return tmp;
|
||||
}
|
||||
return m_devices[_device];
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::CoreIos::closeStream() {
|
||||
ATA_INFO("Close Stream");
|
||||
// Can not close the stream now...
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::CoreIos::startStream() {
|
||||
ATA_INFO("Start Stream");
|
||||
// TODO : Check return ...
|
||||
audio::orchestra::Api::startStream();
|
||||
OSStatus status = AudioOutputUnitStart(m_private->audioUnit);
|
||||
// Can not close the stream now...
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::CoreIos::stopStream() {
|
||||
ATA_INFO("Stop stream");
|
||||
OSStatus status = AudioOutputUnitStop(m_private->audioUnit);
|
||||
// Can not close the stream now...
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::CoreIos::abortStream() {
|
||||
ATA_INFO("Abort Stream");
|
||||
OSStatus status = AudioOutputUnitStop(m_private->audioUnit);
|
||||
// Can not close the stream now...
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
void audio::orchestra::api::CoreIos::callBackEvent(void* _data,
|
||||
int32_t _nbChunk,
|
||||
const audio::Time& _time) {
|
||||
int32_t doStopStream = 0;
|
||||
etk::Vector<enum audio::orchestra::status> status;
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_doConvertBuffer[modeToIdTable(audio::orchestra::mode_output)] == true) {
|
||||
ATA_INFO("get output DATA : " << uint64_t(&m_userBuffer[modeToIdTable(audio::orchestra::mode_output)][0]));
|
||||
doStopStream = m_callback(null,
|
||||
audio::Time(),
|
||||
&m_userBuffer[modeToIdTable(audio::orchestra::mode_output)][0],
|
||||
_time,
|
||||
_nbChunk,
|
||||
status);
|
||||
convertBuffer((char*)_data, &m_userBuffer[modeToIdTable(audio::orchestra::mode_output)][0], m_convertInfo[modeToIdTable(audio::orchestra::mode_output)]);
|
||||
} else {
|
||||
ATA_INFO("have output DATA : " << uint64_t(_data));
|
||||
doStopStream = m_callback(null,
|
||||
_time,
|
||||
_data,
|
||||
audio::Time(),
|
||||
_nbChunk,
|
||||
status);
|
||||
}
|
||||
}
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
ATA_INFO("have input DATA : " << uint64_t(_data));
|
||||
doStopStream = m_callback(_data,
|
||||
_time,
|
||||
null,
|
||||
audio::Time(),
|
||||
_nbChunk,
|
||||
status);
|
||||
}
|
||||
if (doStopStream == 2) {
|
||||
abortStream();
|
||||
return;
|
||||
}
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
}
|
||||
|
||||
|
||||
static OSStatus playbackCallback(void *_userData,
|
||||
AudioUnitRenderActionFlags* _ioActionFlags,
|
||||
const AudioTimeStamp* _inTime,
|
||||
uint32_t _inBusNumber,
|
||||
uint32_t _inNumberFrames,
|
||||
AudioBufferList* _ioData) {
|
||||
if (_userData == null) {
|
||||
ATA_ERROR("callback event ... null pointer");
|
||||
return -1;
|
||||
}
|
||||
audio::Time tmpTimeime;
|
||||
if (_inTime != null) {
|
||||
tmpTimeime = audio::Time(_inTime->mHostTime/1000000000LL, _inTime->mHostTime%1000000000LL);
|
||||
}
|
||||
audio::orchestra::api::CoreIos* myClass = static_cast<audio::orchestra::api::CoreIos*>(_userData);
|
||||
// get all requested buffer :
|
||||
for (int32_t iii=0; iii < _ioData->mNumberBuffers; iii++) {
|
||||
AudioBuffer buffer = _ioData->mBuffers[iii];
|
||||
int32_t numberFrame = buffer.mDataByteSize/2/*stereo*/ /sizeof(int16_t);
|
||||
ATA_INFO("request data size: " << numberFrame << " busNumber=" << _inBusNumber);
|
||||
myClass->callBackEvent(buffer.mData, numberFrame, tmpTimeime);
|
||||
}
|
||||
return noErr;
|
||||
}
|
||||
|
||||
|
||||
bool audio::orchestra::api::CoreIos::open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
ATA_INFO("Probe : device=" << _device << " channels=" << _channels << " firstChannel=" << _firstChannel << " sampleRate=" << _sampleRate);
|
||||
if (_mode != audio::orchestra::mode_output) {
|
||||
ATA_ERROR("Can not start a device input or duplex for CoreIos ...");
|
||||
return false;
|
||||
}
|
||||
bool ret = true;
|
||||
// TODO : This is a bad ack ....
|
||||
m_mode = audio::orchestra::mode_output;
|
||||
// configure Airtaudio internal configuration:
|
||||
m_userFormat = _format;
|
||||
m_nUserChannels[modeToIdTable(_mode)] = _channels;
|
||||
m_bufferSize = 8192;
|
||||
m_sampleRate = _sampleRate;
|
||||
m_doByteSwap[modeToIdTable(_mode)] = false; // for endienness ...
|
||||
|
||||
// TODO : For now, we write it in hard ==> to be update later ...
|
||||
m_deviceFormat[modeToIdTable(_mode)] = audio::format_int16;
|
||||
m_nDeviceChannels[modeToIdTable(_mode)] = 2;
|
||||
m_deviceInterleaved[modeToIdTable(_mode)] = true;
|
||||
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = false;
|
||||
if (m_userFormat != m_deviceFormat[modeToIdTable(_mode)]) {
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
if (m_nUserChannels[modeToIdTable(_mode)] < m_nDeviceChannels[modeToIdTable(_mode)]) {
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
if ( m_deviceInterleaved[modeToIdTable(_mode)] == false
|
||||
&& m_nUserChannels[modeToIdTable(_mode)] > 1) {
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)] == true) {
|
||||
// Allocate necessary internal buffers.
|
||||
uint64_t bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
m_userBuffer[modeToIdTable(_mode)].resize(bufferBytes, 0);
|
||||
if (m_userBuffer[modeToIdTable(_mode)].size() == 0) {
|
||||
ATA_ERROR("error allocating user buffer memory.");
|
||||
}
|
||||
setConvertInfo(_mode, _firstChannel);
|
||||
}
|
||||
ATA_INFO("device format : " << m_deviceFormat[modeToIdTable(_mode)] << " user format : " << m_userFormat);
|
||||
ATA_INFO("device channels : " << m_nDeviceChannels[modeToIdTable(_mode)] << " user channels : " << m_nUserChannels[modeToIdTable(_mode)]);
|
||||
ATA_INFO("do convert buffer : " << m_doConvertBuffer[modeToIdTable(_mode)]);
|
||||
if (ret == false) {
|
||||
ATA_ERROR("Can not open device.");
|
||||
}
|
||||
|
||||
// Configure IOs interface:
|
||||
OSStatus status;
|
||||
|
||||
// Describe audio component
|
||||
AudioComponentDescription desc;
|
||||
desc.componentType = kAudioUnitType_Output;
|
||||
desc.componentSubType = kAudioUnitSubType_RemoteIO;
|
||||
desc.componentFlags = 0;
|
||||
desc.componentFlagsMask = 0;
|
||||
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
|
||||
|
||||
// Get component
|
||||
AudioComponent inputComponent = AudioComponentFindNext(null, &desc);
|
||||
|
||||
// Get audio units
|
||||
status = AudioComponentInstanceNew(inputComponent, &m_private->audioUnit);
|
||||
if (status != 0) {
|
||||
ATA_ERROR("can not create an audio intance...");
|
||||
}
|
||||
|
||||
uint32_t flag = 1;
|
||||
// Enable IO for playback
|
||||
status = AudioUnitSetProperty(m_private->audioUnit,
|
||||
kAudioOutputUnitProperty_EnableIO,
|
||||
kAudioUnitScope_Output,
|
||||
kOutputBus,
|
||||
&flag,
|
||||
sizeof(flag));
|
||||
if (status != 0) {
|
||||
ATA_ERROR("can not request audio autorisation...");
|
||||
}
|
||||
|
||||
// Describe format
|
||||
AudioStreamBasicDescription audioFormat;
|
||||
audioFormat.mSampleRate = 48000.00;
|
||||
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
||||
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
|
||||
audioFormat.mFramesPerPacket = 1; //
|
||||
audioFormat.mChannelsPerFrame = 2; // stereo
|
||||
audioFormat.mBitsPerChannel = sizeof(short) * 8;
|
||||
audioFormat.mBytesPerPacket = sizeof(short) * audioFormat.mChannelsPerFrame;
|
||||
audioFormat.mBytesPerFrame = sizeof(short) * audioFormat.mChannelsPerFrame;
|
||||
audioFormat.mReserved = 0;
|
||||
// Apply format
|
||||
status = AudioUnitSetProperty(m_private->audioUnit,
|
||||
kAudioUnitProperty_StreamFormat,
|
||||
kAudioUnitScope_Input,
|
||||
kOutputBus,
|
||||
&audioFormat,
|
||||
sizeof(audioFormat));
|
||||
if (status != 0) {
|
||||
ATA_ERROR("can not set stream properties...");
|
||||
}
|
||||
|
||||
|
||||
// Set output callback
|
||||
AURenderCallbackStruct callbackStruct;
|
||||
callbackStruct.inputProc = &playbackCallback;
|
||||
callbackStruct.inputProcRefCon = this;
|
||||
status = AudioUnitSetProperty(m_private->audioUnit,
|
||||
kAudioUnitProperty_SetRenderCallback,
|
||||
kAudioUnitScope_Global,
|
||||
kOutputBus,
|
||||
&callbackStruct,
|
||||
sizeof(callbackStruct));
|
||||
if (status != 0) {
|
||||
ATA_ERROR("can not set Callback...");
|
||||
}
|
||||
|
||||
// Initialise
|
||||
status = AudioUnitInitialize(m_private->audioUnit);
|
||||
if (status != 0) {
|
||||
ATA_ERROR("can not initialize...");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
1399
audio/orchestra/api/Ds.cpp
Normal file
1399
audio/orchestra/api/Ds.cpp
Normal file
File diff suppressed because it is too large
Load Diff
54
audio/orchestra/api/Ds.hpp
Normal file
54
audio/orchestra/api/Ds.hpp
Normal file
@ -0,0 +1,54 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef ORCHESTRA_BUILD_DS
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class DsPrivate;
|
||||
class Ds: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
Ds();
|
||||
virtual ~Ds();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typeDs;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEvent();
|
||||
private:
|
||||
static void dsCallbackEvent(void *_userData);
|
||||
ememory::SharedPtr<DsPrivate> m_private;
|
||||
bool m_coInitialized;
|
||||
bool m_buffersRolling;
|
||||
long m_duplexPrerollBytes;
|
||||
bool open(uint32_t _device,
|
||||
enum audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
enum audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
60
audio/orchestra/api/Dummy.cpp
Normal file
60
audio/orchestra/api/Dummy.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if defined(ORCHESTRA_BUILD_DUMMY)
|
||||
#include <audio/orchestra/api/Dummy.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
|
||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Dummy::create() {
|
||||
return ememory::SharedPtr<audio::orchestra::api::Dummy>(ETK_NEW(audio::orchestra::api::Dummy));
|
||||
}
|
||||
|
||||
|
||||
audio::orchestra::api::Dummy::Dummy() {
|
||||
ATA_WARNING("This class provides no functionality.");
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::Dummy::getDeviceCount() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Dummy::getDeviceInfo(uint32_t _device) {
|
||||
(void)_device;
|
||||
return audio::orchestra::DeviceInfo();
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Dummy::closeStream() {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Dummy::startStream() {
|
||||
// TODO : Check return ...
|
||||
audio::orchestra::Api::startStream();
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Dummy::stopStream() {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Dummy::abortStream() {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
bool audio::orchestra::api::Dummy::open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
44
audio/orchestra/api/Dummy.hpp
Normal file
44
audio/orchestra/api/Dummy.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef ORCHESTRA_BUILD_DUMMY
|
||||
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class Dummy: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
Dummy();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typeDummy;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
private:
|
||||
bool open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
712
audio/orchestra/api/Jack.cpp
Normal file
712
audio/orchestra/api/Jack.cpp
Normal file
@ -0,0 +1,712 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
// must run before :
|
||||
#if defined(ORCHESTRA_BUILD_JACK)
|
||||
extern "C" {
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
}
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <ethread/tools.hpp>
|
||||
#include <audio/orchestra/api/Jack.hpp>
|
||||
|
||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Jack::create() {
|
||||
return ememory::SharedPtr<audio::orchestra::api::Jack>(ETK_NEW(audio::orchestra::api::Jack));
|
||||
}
|
||||
|
||||
|
||||
// JACK is a low-latency audio server, originally written for the
|
||||
// GNU/Linux operating system and now also ported to OS-X. It can
|
||||
// connect a number of different applications to an audio device, as
|
||||
// well as allowing them to share audio between themselves.
|
||||
//
|
||||
// When using JACK with RtAudio, "devices" refer to JACK clients that
|
||||
// have ports connected to the server. The JACK server is typically
|
||||
// started in a terminal as follows:
|
||||
//
|
||||
// .jackd -d alsa -d hw:0
|
||||
//
|
||||
// or through an interface program such as qjackctl. Many of the
|
||||
// parameters normally set for a stream are fixed by the JACK server
|
||||
// and can be specified when the JACK server is started. In
|
||||
// particular,
|
||||
//
|
||||
// jackd -d alsa -d hw:0 -r 44100 -p 512 -n 4
|
||||
// jackd -r -d alsa -r 48000
|
||||
//
|
||||
// specifies a sample rate of 44100 Hz, a buffer size of 512 sample
|
||||
// frames, and number of buffers = 4. Once the server is running, it
|
||||
// is not possible to override these values. If the values are not
|
||||
// specified in the command-line, the JACK server uses default values.
|
||||
//
|
||||
// The JACK server does not have to be running when an instance of
|
||||
// audio::orchestra::Jack is created, though the function getDeviceCount() will
|
||||
// report 0 devices found until JACK has been started. When no
|
||||
// devices are available (i.e., the JACK server is not running), a
|
||||
// stream cannot be opened.
|
||||
|
||||
#include <jack/jack.h>
|
||||
extern "C" {
|
||||
#include <stdio.h>
|
||||
}
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class JackPrivate {
|
||||
public:
|
||||
jack_client_t *client;
|
||||
jack_port_t **ports[2];
|
||||
etk::String deviceName[2];
|
||||
bool xrun[2];
|
||||
ethread::Semaphore m_semaphore;
|
||||
int32_t drainCounter; // Tracks callback counts when draining
|
||||
bool internalDrain; // Indicates if stop is initiated from callback or not.
|
||||
|
||||
JackPrivate() :
|
||||
client(0),
|
||||
drainCounter(0),
|
||||
internalDrain(false) {
|
||||
ports[0] = 0;
|
||||
ports[1] = 0;
|
||||
xrun[0] = false;
|
||||
xrun[1] = false;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
audio::orchestra::api::Jack::Jack() :
|
||||
m_private(ETK_NEW(audio::orchestra::api::JackPrivate)) {
|
||||
// Nothing to do here.
|
||||
}
|
||||
|
||||
audio::orchestra::api::Jack::~Jack() {
|
||||
if (m_state != audio::orchestra::state::closed) {
|
||||
closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::Jack::getDeviceCount() {
|
||||
// See if we can become a jack client.
|
||||
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption;
|
||||
jack_status_t *status = null;
|
||||
jack_client_t *client = jack_client_open("orchestraJackCount", options, status);
|
||||
if (client == null) {
|
||||
return 0;
|
||||
}
|
||||
const char **ports;
|
||||
etk::String port, previousPort;
|
||||
uint32_t nChannels = 0, nDevices = 0;
|
||||
ports = jack_get_ports(client, null, null, 0);
|
||||
if (ports) {
|
||||
// Parse the port names up to the first colon (:).
|
||||
size_t iColon = 0;
|
||||
do {
|
||||
port = (char *) ports[ nChannels ];
|
||||
iColon = port.find(":");
|
||||
if (iColon != etk::String::npos) {
|
||||
port = port.extract(0, iColon + 1);
|
||||
if (port != previousPort) {
|
||||
nDevices++;
|
||||
previousPort = port;
|
||||
}
|
||||
}
|
||||
} while (ports[++nChannels]);
|
||||
free(ports);
|
||||
ports = null;
|
||||
}
|
||||
jack_client_close(client);
|
||||
return nDevices*2;
|
||||
}
|
||||
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Jack::getDeviceInfo(uint32_t _device) {
|
||||
audio::orchestra::DeviceInfo info;
|
||||
jack_options_t options = (jack_options_t) (JackNoStartServer); //JackNullOption
|
||||
jack_status_t *status = null;
|
||||
jack_client_t *client = jack_client_open("orchestraJackInfo", options, status);
|
||||
if (client == null) {
|
||||
ATA_ERROR("Jack server not found or connection error!");
|
||||
// TODO : audio::orchestra::error_warning;
|
||||
info.clear();
|
||||
return info;
|
||||
}
|
||||
const char **ports;
|
||||
etk::String port, previousPort;
|
||||
uint32_t nPorts = 0, nDevices = 0;
|
||||
ports = jack_get_ports(client, null, null, 0);
|
||||
int32_t deviceID = _device/2;
|
||||
info.input = _device%2==0?true:false; // note that jack sens are inverted
|
||||
if (ports) {
|
||||
// Parse the port names up to the first colon (:).
|
||||
size_t iColon = 0;
|
||||
do {
|
||||
port = (char *) ports[nPorts];
|
||||
iColon = port.find(":");
|
||||
if (iColon != etk::String::npos) {
|
||||
port = port.extract(0, iColon);
|
||||
if (port != previousPort) {
|
||||
if (nDevices == deviceID) {
|
||||
info.name = port;
|
||||
}
|
||||
nDevices++;
|
||||
previousPort = port;
|
||||
}
|
||||
}
|
||||
} while (ports[++nPorts]);
|
||||
free(ports);
|
||||
}
|
||||
if (deviceID >= nDevices) {
|
||||
jack_client_close(client);
|
||||
ATA_ERROR("device ID is invalid!");
|
||||
// TODO : audio::orchestra::error_invalidUse;
|
||||
return info;
|
||||
}
|
||||
// Get the current jack server sample rate.
|
||||
info.sampleRates.clear();
|
||||
info.sampleRates.pushBack(jack_get_sample_rate(client));
|
||||
if (info.input == true) {
|
||||
ports = jack_get_ports(client, info.name.c_str(), null, JackPortIsOutput);
|
||||
if (ports) {
|
||||
int32_t iii=0;
|
||||
while (ports[iii]) {
|
||||
ATA_ERROR(" ploppp='" << ports[iii] << "'");
|
||||
info.channels.pushBack(audio::channel_unknow);
|
||||
iii++;
|
||||
}
|
||||
free(ports);
|
||||
}
|
||||
} else {
|
||||
ports = jack_get_ports(client, info.name.c_str(), null, JackPortIsInput);
|
||||
if (ports) {
|
||||
int32_t iii=0;
|
||||
while (ports[iii]) {
|
||||
ATA_ERROR(" ploppp='" << ports[iii] << "'");
|
||||
info.channels.pushBack(audio::channel_unknow);
|
||||
iii++;
|
||||
}
|
||||
free(ports);
|
||||
}
|
||||
}
|
||||
if (info.channels.size() == 0) {
|
||||
jack_client_close(client);
|
||||
ATA_ERROR("error determining Jack input/output channels!");
|
||||
// TODO : audio::orchestra::error_warning;
|
||||
info.clear();
|
||||
return info;
|
||||
}
|
||||
// Jack always uses 32-bit floats.
|
||||
info.nativeFormats.pushBack(audio::format_float);
|
||||
// Jack doesn't provide default devices so we'll use the first available one.
|
||||
if (deviceID == 0) {
|
||||
info.isDefault = true;
|
||||
}
|
||||
jack_client_close(client);
|
||||
info.isCorrect = true;
|
||||
return info;
|
||||
}
|
||||
|
||||
int32_t audio::orchestra::api::Jack::jackCallbackHandler(jack_nframes_t _nframes, void* _userData) {
|
||||
ATA_VERBOSE("Jack callback: [BEGIN] " << uint64_t(_userData));
|
||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||
if (myClass->callbackEvent((uint64_t)_nframes) == false) {
|
||||
ATA_VERBOSE("Jack callback: [END] 1");
|
||||
return 1;
|
||||
}
|
||||
ATA_VERBOSE("Jack callback: [END] 0");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void audio::orchestra::api::Jack::jackShutdown(void* _userData) {
|
||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||
// Check current stream state. If stopped, then we'll assume this
|
||||
// was called as a result of a call to audio::orchestra::api::Jack::stopStream (the
|
||||
// deactivation of a client handle causes this function to be called).
|
||||
// If not, we'll assume the Jack server is shutting down or some
|
||||
// other problem occurred and we should close the stream.
|
||||
if (myClass->isStreamRunning() == false) {
|
||||
return;
|
||||
}
|
||||
ETK_NEW(ethread::Thread, [=](){myClass->closeStream();});
|
||||
ATA_ERROR("The Jack server is shutting down this client ... stream stopped and closed!!");
|
||||
}
|
||||
|
||||
int32_t audio::orchestra::api::Jack::jackXrun(void* _userData) {
|
||||
audio::orchestra::api::Jack* myClass = reinterpret_cast<audio::orchestra::api::Jack*>(_userData);
|
||||
if (myClass->m_private->ports[0]) {
|
||||
myClass->m_private->xrun[0] = true;
|
||||
}
|
||||
if (myClass->m_private->ports[1]) {
|
||||
myClass->m_private->xrun[1] = true;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool audio::orchestra::api::Jack::open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t* _bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
// Look for jack server and try to become a client (only do once per stream).
|
||||
jack_client_t *client = 0;
|
||||
if ( _mode == audio::orchestra::mode_output
|
||||
|| ( _mode == audio::orchestra::mode_input
|
||||
&& m_mode != audio::orchestra::mode_output)) {
|
||||
jack_options_t jackoptions = (jack_options_t) (JackNoStartServer); //JackNullOption;
|
||||
jack_status_t *status = null;
|
||||
if (_options.streamName.size() != 0) {
|
||||
client = jack_client_open(_options.streamName.c_str(), jackoptions, status);
|
||||
} else {
|
||||
client = jack_client_open("orchestraJack", jackoptions, status);
|
||||
}
|
||||
if (client == 0) {
|
||||
ATA_ERROR("Jack server not found or connection error!");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// The handle must have been created on an earlier pass.
|
||||
client = m_private->client;
|
||||
}
|
||||
const char **ports;
|
||||
etk::String port, previousPort, deviceName;
|
||||
uint32_t nPorts = 0, nDevices = 0;
|
||||
int32_t deviceID = _device/2;
|
||||
bool isInput = _device%2==0?true:false;
|
||||
ports = jack_get_ports(client, null, null, 0);
|
||||
if (ports) {
|
||||
// Parse the port names up to the first colon (:).
|
||||
size_t iColon = 0;
|
||||
do {
|
||||
port = (char *) ports[ nPorts ];
|
||||
iColon = port.find(":");
|
||||
if (iColon != etk::String::npos) {
|
||||
port = port.extract(0, iColon);
|
||||
if (port != previousPort) {
|
||||
if (nDevices == deviceID) {
|
||||
deviceName = port;
|
||||
}
|
||||
nDevices++;
|
||||
previousPort = port;
|
||||
}
|
||||
}
|
||||
} while (ports[++nPorts]);
|
||||
free(ports);
|
||||
}
|
||||
if (_device >= nDevices) {
|
||||
ATA_ERROR("device ID is invalid!");
|
||||
return false;
|
||||
}
|
||||
// Count the available ports containing the client name as device
|
||||
// channels. Jack "input ports" equal RtAudio output channels.
|
||||
uint32_t nChannels = 0;
|
||||
uint64_t flag = JackPortIsInput;
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
flag = JackPortIsOutput;
|
||||
}
|
||||
ports = jack_get_ports(client, deviceName.c_str(), null, flag);
|
||||
if (ports) {
|
||||
while (ports[ nChannels ]) {
|
||||
nChannels++;
|
||||
}
|
||||
free(ports);
|
||||
}
|
||||
// Compare the jack ports for specified client to the requested number of channels.
|
||||
if (nChannels < (_channels + _firstChannel)) {
|
||||
ATA_ERROR("requested number of channels (" << _channels << ") + offset (" << _firstChannel << ") not found for specified device (" << _device << ":" << deviceName << ").");
|
||||
return false;
|
||||
}
|
||||
// Check the jack server sample rate.
|
||||
uint32_t jackRate = jack_get_sample_rate(client);
|
||||
if (_sampleRate != jackRate) {
|
||||
jack_client_close(client);
|
||||
ATA_ERROR("the requested sample rate (" << _sampleRate << ") is different than the JACK server rate (" << jackRate << ").");
|
||||
return false;
|
||||
}
|
||||
m_sampleRate = jackRate;
|
||||
// Get the latency of the JACK port.
|
||||
ports = jack_get_ports(client, deviceName.c_str(), null, flag);
|
||||
if (ports[ _firstChannel ]) {
|
||||
// Added by Ge Wang
|
||||
jack_latency_callback_mode_t cbmode = (_mode == audio::orchestra::mode_input ? JackCaptureLatency : JackPlaybackLatency);
|
||||
// the range (usually the min and max are equal)
|
||||
jack_latency_range_t latrange; latrange.min = latrange.max = 0;
|
||||
// get the latency range
|
||||
jack_port_get_latency_range(jack_port_by_name(client, ports[_firstChannel]), cbmode, &latrange);
|
||||
// be optimistic, use the min!
|
||||
m_latency[modeToIdTable(_mode)] = latrange.min;
|
||||
//m_latency[modeToIdTable(_mode)] = jack_port_get_latency(jack_port_by_name(client, ports[ _firstChannel ]));
|
||||
}
|
||||
free(ports);
|
||||
// The jack server always uses 32-bit floating-point data.
|
||||
m_deviceFormat[modeToIdTable(_mode)] = audio::format_float;
|
||||
m_userFormat = _format;
|
||||
// Jack always uses non-interleaved buffers.
|
||||
m_deviceInterleaved[modeToIdTable(_mode)] = false;
|
||||
// Jack always provides host byte-ordered data.
|
||||
m_doByteSwap[modeToIdTable(_mode)] = false;
|
||||
// Get the buffer size. The buffer size and number of buffers
|
||||
// (periods) is set when the jack server is started.
|
||||
m_bufferSize = (int) jack_get_buffer_size(client);
|
||||
*_bufferSize = m_bufferSize;
|
||||
m_nDeviceChannels[modeToIdTable(_mode)] = _channels;
|
||||
m_nUserChannels[modeToIdTable(_mode)] = _channels;
|
||||
// Set flags for buffer conversion.
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = false;
|
||||
if (m_userFormat != m_deviceFormat[modeToIdTable(_mode)]) {
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||
ATA_CRITICAL("Can not update format ==> use RIVER lib for this ...");
|
||||
}
|
||||
if ( m_deviceInterleaved[modeToIdTable(_mode)] == false
|
||||
&& m_nUserChannels[modeToIdTable(_mode)] > 1) {
|
||||
ATA_ERROR("Reorder channel for the interleaving properties ...");
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = true;
|
||||
}
|
||||
// Allocate our JackHandle structure for the stream.
|
||||
m_private->client = client;
|
||||
m_private->deviceName[modeToIdTable(_mode)] = deviceName;
|
||||
// Allocate necessary internal buffers.
|
||||
uint64_t bufferBytes;
|
||||
bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * *_bufferSize * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
ATA_VERBOSE("allocate : nbChannel=" << m_nUserChannels[modeToIdTable(_mode)] << " bufferSize=" << *_bufferSize << " format=" << m_deviceFormat[modeToIdTable(_mode)] << "=" << audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]));
|
||||
m_userBuffer[modeToIdTable(_mode)].resize(bufferBytes, 0);
|
||||
if (m_userBuffer[modeToIdTable(_mode)].size() == 0) {
|
||||
ATA_ERROR("error allocating user buffer memory.");
|
||||
goto error;
|
||||
}
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
bufferBytes = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
} else { // _mode == audio::orchestra::mode_input
|
||||
bufferBytes = m_nDeviceChannels[1] * audio::getFormatBytes(m_deviceFormat[1]);
|
||||
if (m_mode == audio::orchestra::mode_output && m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes < bytesOut) {
|
||||
makeBuffer = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (makeBuffer) {
|
||||
bufferBytes *= *_bufferSize;
|
||||
if (m_deviceBuffer) free(m_deviceBuffer);
|
||||
m_deviceBuffer = (char *) calloc(bufferBytes, 1);
|
||||
if (m_deviceBuffer == null) {
|
||||
ATA_ERROR("error allocating device buffer memory.");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Allocate memory for the Jack ports (channels) identifiers.
|
||||
m_private->ports[modeToIdTable(_mode)] = (jack_port_t **) malloc (sizeof (jack_port_t *) * _channels);
|
||||
if (m_private->ports[modeToIdTable(_mode)] == null) {
|
||||
ATA_ERROR("error allocating port memory.");
|
||||
goto error;
|
||||
}
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
m_channelOffset[modeToIdTable(_mode)] = _firstChannel;
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
&& _mode == audio::orchestra::mode_input) {
|
||||
// We had already set up the stream for output.
|
||||
m_mode = audio::orchestra::mode_duplex;
|
||||
} else {
|
||||
m_mode = _mode;
|
||||
jack_set_process_callback(m_private->client, &audio::orchestra::api::Jack::jackCallbackHandler, this);
|
||||
jack_set_xrun_callback(m_private->client, &audio::orchestra::api::Jack::jackXrun, this);
|
||||
jack_on_shutdown(m_private->client, &audio::orchestra::api::Jack::jackShutdown, this);
|
||||
}
|
||||
// Register our ports.
|
||||
char label[64];
|
||||
if (_mode == audio::orchestra::mode_output) {
|
||||
for (uint32_t i=0; i<m_nUserChannels[0]; i++) {
|
||||
snprintf(label, 64, "outport %d", i);
|
||||
m_private->ports[0][i] = jack_port_register(m_private->client,
|
||||
(const char *)label,
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsOutput,
|
||||
0);
|
||||
}
|
||||
} else {
|
||||
for (uint32_t i=0; i<m_nUserChannels[1]; i++) {
|
||||
snprintf(label, 64, "inport %d", i);
|
||||
m_private->ports[1][i] = jack_port_register(m_private->client,
|
||||
(const char *)label,
|
||||
JACK_DEFAULT_AUDIO_TYPE,
|
||||
JackPortIsInput,
|
||||
0);
|
||||
}
|
||||
}
|
||||
// Setup the buffer conversion information structure. We don't use
|
||||
// buffers to do channel offsets, so we override that parameter
|
||||
// here.
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
setConvertInfo(_mode, 0);
|
||||
}
|
||||
return true;
|
||||
error:
|
||||
jack_client_close(m_private->client);
|
||||
if (m_private->ports[0] != null) {
|
||||
free(m_private->ports[0]);
|
||||
m_private->ports[0] = null;
|
||||
}
|
||||
if (m_private->ports[1] != null) {
|
||||
free(m_private->ports[1]);
|
||||
m_private->ports[1] = null;
|
||||
}
|
||||
for (int32_t iii=0; iii<2; ++iii) {
|
||||
m_userBuffer[iii].clear();
|
||||
}
|
||||
if (m_deviceBuffer) {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Jack::closeStream() {
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("no open stream to close!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if (m_private != null) {
|
||||
if (m_state == audio::orchestra::state::running) {
|
||||
jack_deactivate(m_private->client);
|
||||
}
|
||||
jack_client_close(m_private->client);
|
||||
}
|
||||
if (m_private->ports[0] != null) {
|
||||
free(m_private->ports[0]);
|
||||
m_private->ports[0] = null;
|
||||
}
|
||||
if (m_private->ports[1] != null) {
|
||||
free(m_private->ports[1]);
|
||||
m_private->ports[1] = null;
|
||||
}
|
||||
for (int32_t i=0; i<2; i++) {
|
||||
m_userBuffer[i].clear();
|
||||
}
|
||||
if (m_deviceBuffer) {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = null;
|
||||
}
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
m_state = audio::orchestra::state::closed;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Jack::startStream() {
|
||||
// TODO : Check return ...
|
||||
audio::orchestra::Api::startStream();
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
int32_t result = jack_activate(m_private->client);
|
||||
if (result) {
|
||||
ATA_ERROR("unable to activate JACK client!");
|
||||
goto unlock;
|
||||
}
|
||||
const char **ports;
|
||||
// Get the list of available ports.
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
result = 1;
|
||||
ports = jack_get_ports(m_private->client, m_private->deviceName[0].c_str(), null, JackPortIsInput);
|
||||
if (ports == null) {
|
||||
ATA_ERROR("error determining available JACK input ports!");
|
||||
goto unlock;
|
||||
}
|
||||
// Now make the port connections. Since RtAudio wasn't designed to
|
||||
// allow the user to select particular channels of a device, we'll
|
||||
// just open the first "nChannels" ports with offset.
|
||||
for (uint32_t i=0; i<m_nUserChannels[0]; i++) {
|
||||
result = 1;
|
||||
if (ports[ m_channelOffset[0] + i ])
|
||||
result = jack_connect(m_private->client, jack_port_name(m_private->ports[0][i]), ports[ m_channelOffset[0] + i ]);
|
||||
if (result) {
|
||||
free(ports);
|
||||
ATA_ERROR("error connecting output ports!");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
free(ports);
|
||||
}
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
result = 1;
|
||||
ports = jack_get_ports(m_private->client, m_private->deviceName[1].c_str(), null, JackPortIsOutput);
|
||||
if (ports == null) {
|
||||
ATA_ERROR("error determining available JACK output ports!");
|
||||
goto unlock;
|
||||
}
|
||||
// Now make the port connections. See note above.
|
||||
for (uint32_t i=0; i<m_nUserChannels[1]; i++) {
|
||||
result = 1;
|
||||
if (ports[ m_channelOffset[1] + i ]) {
|
||||
result = jack_connect(m_private->client, ports[ m_channelOffset[1] + i ], jack_port_name(m_private->ports[1][i]));
|
||||
}
|
||||
if (result) {
|
||||
free(ports);
|
||||
ATA_ERROR("error connecting input ports!");
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
free(ports);
|
||||
}
|
||||
m_private->drainCounter = 0;
|
||||
m_private->internalDrain = false;
|
||||
m_state = audio::orchestra::state::running;
|
||||
unlock:
|
||||
if (result == 0) {
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Jack::stopStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->drainCounter == 0) {
|
||||
m_private->drainCounter = 2;
|
||||
m_private->m_semaphore.wait();
|
||||
}
|
||||
}
|
||||
jack_deactivate(m_private->client);
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Jack::abortStream() {
|
||||
if (verifyStream() != audio::orchestra::error_none) {
|
||||
return audio::orchestra::error_fail;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_private->drainCounter = 2;
|
||||
return stopStream();
|
||||
}
|
||||
|
||||
bool audio::orchestra::api::Jack::callbackEvent(uint64_t _nframes) {
|
||||
if ( m_state == audio::orchestra::state::stopped
|
||||
|| m_state == audio::orchestra::state::stopping) {
|
||||
return true;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return false;
|
||||
}
|
||||
if (m_bufferSize != _nframes) {
|
||||
ATA_ERROR("the JACK buffer size has changed ... cannot process!");
|
||||
return false;
|
||||
}
|
||||
// Check if we were draining the stream and signal is finished.
|
||||
if (m_private->drainCounter > 3) {
|
||||
m_state = audio::orchestra::state::stopping;
|
||||
if (m_private->internalDrain == true) {
|
||||
ETK_NEW(ethread::Thread, [&](){stopStream();}, "Jack_stopStream");
|
||||
} else {
|
||||
m_private->m_semaphore.post();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// Invoke user callback first, to get fresh output data.
|
||||
if (m_private->drainCounter == 0) {
|
||||
audio::Time streamTime = getStreamTime();
|
||||
etk::Vector<enum audio::orchestra::status> status;
|
||||
if (m_mode != audio::orchestra::mode_input && m_private->xrun[0] == true) {
|
||||
status.pushBack(audio::orchestra::status::underflow);
|
||||
m_private->xrun[0] = false;
|
||||
}
|
||||
if (m_mode != audio::orchestra::mode_output && m_private->xrun[1] == true) {
|
||||
status.pushBack(audio::orchestra::status::overflow);
|
||||
m_private->xrun[1] = false;
|
||||
}
|
||||
int32_t cbReturnValue = m_callback(&m_userBuffer[1][0],
|
||||
streamTime,
|
||||
&m_userBuffer[0][0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (cbReturnValue == 2) {
|
||||
m_state = audio::orchestra::state::stopping;
|
||||
m_private->drainCounter = 2;
|
||||
ETK_NEW(ethread::Thread, [&](){stopStream();}, "Jack_stopStream2");
|
||||
return true;
|
||||
}
|
||||
else if (cbReturnValue == 1) {
|
||||
m_private->drainCounter = 1;
|
||||
m_private->internalDrain = true;
|
||||
}
|
||||
}
|
||||
jack_default_audio_sample_t *jackbuffer;
|
||||
uint64_t bufferBytes = _nframes * sizeof(jack_default_audio_sample_t);
|
||||
if ( m_mode == audio::orchestra::mode_output
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_private->drainCounter > 1) { // write zeros to the output stream
|
||||
for (uint32_t i=0; i<m_nDeviceChannels[0]; i++) {
|
||||
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(m_private->ports[0][i], (jack_nframes_t) _nframes);
|
||||
memset(jackbuffer, 0, bufferBytes);
|
||||
}
|
||||
} else if (m_doConvertBuffer[0]) {
|
||||
convertBuffer(m_deviceBuffer, &m_userBuffer[0][0], m_convertInfo[0]);
|
||||
for (uint32_t i=0; i<m_nDeviceChannels[0]; i++) {
|
||||
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(m_private->ports[0][i], (jack_nframes_t) _nframes);
|
||||
memcpy(jackbuffer, &m_deviceBuffer[i*bufferBytes], bufferBytes);
|
||||
}
|
||||
} else { // no buffer conversion
|
||||
for (uint32_t i=0; i<m_nUserChannels[0]; i++) {
|
||||
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(m_private->ports[0][i], (jack_nframes_t) _nframes);
|
||||
memcpy(jackbuffer, &m_userBuffer[0][i*bufferBytes], bufferBytes);
|
||||
}
|
||||
}
|
||||
if (m_private->drainCounter) {
|
||||
m_private->drainCounter++;
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
if ( m_mode == audio::orchestra::mode_input
|
||||
|| m_mode == audio::orchestra::mode_duplex) {
|
||||
if (m_doConvertBuffer[1]) {
|
||||
for (uint32_t i=0; i<m_nDeviceChannels[1]; i++) {
|
||||
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(m_private->ports[1][i], (jack_nframes_t) _nframes);
|
||||
memcpy(&m_deviceBuffer[i*bufferBytes], jackbuffer, bufferBytes);
|
||||
}
|
||||
convertBuffer(&m_userBuffer[1][0], m_deviceBuffer, m_convertInfo[1]);
|
||||
} else {
|
||||
// no buffer conversion
|
||||
for (uint32_t i=0; i<m_nUserChannels[1]; i++) {
|
||||
jackbuffer = (jack_default_audio_sample_t *) jack_port_get_buffer(m_private->ports[1][i], (jack_nframes_t) _nframes);
|
||||
memcpy(&m_userBuffer[1][i*bufferBytes], jackbuffer, bufferBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
56
audio/orchestra/api/Jack.hpp
Normal file
56
audio/orchestra/api/Jack.hpp
Normal file
@ -0,0 +1,56 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef ORCHESTRA_BUILD_JACK
|
||||
|
||||
#include <jack/jack.h>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class JackPrivate;
|
||||
class Jack: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
Jack();
|
||||
virtual ~Jack();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typeJack;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
long getStreamLatency();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
bool callbackEvent(uint64_t _nframes);
|
||||
private:
|
||||
static int32_t jackXrun(void* _userData);
|
||||
static void jackShutdown(void* _userData);
|
||||
static int32_t jackCallbackHandler(jack_nframes_t _nframes, void* _userData);
|
||||
private:
|
||||
ememory::SharedPtr<JackPrivate> m_private;
|
||||
bool open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
412
audio/orchestra/api/Pulse.cpp
Normal file
412
audio/orchestra/api/Pulse.cpp
Normal file
@ -0,0 +1,412 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
|
||||
#if defined(ORCHESTRA_BUILD_PULSE)
|
||||
|
||||
extern "C" {
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
}
|
||||
#include <audio/orchestra/Interface.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <pulse/error.h>
|
||||
#include <pulse/simple.h>
|
||||
#include <ethread/tools.hpp>
|
||||
#include <audio/orchestra/api/PulseDeviceList.hpp>
|
||||
#include <audio/orchestra/api/Pulse.hpp>
|
||||
|
||||
ememory::SharedPtr<audio::orchestra::Api> audio::orchestra::api::Pulse::create() {
|
||||
return ememory::SharedPtr<audio::orchestra::api::Pulse>(ETK_NEW(audio::orchestra::api::Pulse));
|
||||
}
|
||||
|
||||
|
||||
static const uint32_t SUPPORTED_SAMPLERATES[] = {
|
||||
8000,
|
||||
16000,
|
||||
22050,
|
||||
32000,
|
||||
44100,
|
||||
48000,
|
||||
96000,
|
||||
0
|
||||
};
|
||||
|
||||
struct rtaudio_pa_format_mapping_t {
|
||||
enum audio::format airtaudio_format;
|
||||
pa_sample_format_t pa_format;
|
||||
};
|
||||
|
||||
static const rtaudio_pa_format_mapping_t supported_sampleformats[] = {
|
||||
{audio::format_int16, PA_SAMPLE_S16LE},
|
||||
{audio::format_int32, PA_SAMPLE_S32LE},
|
||||
{audio::format_float, PA_SAMPLE_FLOAT32LE},
|
||||
{audio::format_unknow, PA_SAMPLE_INVALID}};
|
||||
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class PulsePrivate {
|
||||
public:
|
||||
pa_simple* handle;
|
||||
ememory::SharedPtr<ethread::Thread> thread;
|
||||
bool threadRunning;
|
||||
ethread::Semaphore m_semaphore;
|
||||
bool runnable;
|
||||
PulsePrivate() :
|
||||
handle(0),
|
||||
threadRunning(false),
|
||||
runnable(false) {
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
audio::orchestra::api::Pulse::Pulse() :
|
||||
m_private(ETK_NEW(audio::orchestra::api::PulsePrivate)) {
|
||||
|
||||
}
|
||||
|
||||
audio::orchestra::api::Pulse::~Pulse() {
|
||||
if (m_state != audio::orchestra::state::closed) {
|
||||
closeStream();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t audio::orchestra::api::Pulse::getDeviceCount() {
|
||||
#if 1
|
||||
etk::Vector<audio::orchestra::DeviceInfo> list = audio::orchestra::api::pulse::getDeviceList();
|
||||
return list.size();
|
||||
#else
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
audio::orchestra::DeviceInfo audio::orchestra::api::Pulse::getDeviceInfo(uint32_t _device) {
|
||||
etk::Vector<audio::orchestra::DeviceInfo> list = audio::orchestra::api::pulse::getDeviceList();
|
||||
if (_device >= list.size()) {
|
||||
ATA_ERROR("Request device out of IDs:" << _device << " >= " << list.size());
|
||||
return audio::orchestra::DeviceInfo();
|
||||
}
|
||||
return list[_device];
|
||||
}
|
||||
|
||||
|
||||
|
||||
void audio::orchestra::api::Pulse::callbackEvent() {
|
||||
ethread::setName("Pulse IO-" + m_name);
|
||||
while (m_private->threadRunning == true) {
|
||||
callbackEventOneCycle();
|
||||
}
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Pulse::closeStream() {
|
||||
m_private->threadRunning = false;
|
||||
m_mutex.lock();
|
||||
if (m_state == audio::orchestra::state::stopped) {
|
||||
m_private->runnable = true;
|
||||
m_private->m_semaphore.post();;
|
||||
}
|
||||
m_mutex.unLock();
|
||||
m_private->thread->join();
|
||||
if (m_mode == audio::orchestra::mode_output) {
|
||||
pa_simple_flush(m_private->handle, null);
|
||||
}
|
||||
pa_simple_free(m_private->handle);
|
||||
m_private->handle = null;
|
||||
m_userBuffer[0].clear();
|
||||
m_userBuffer[1].clear();
|
||||
m_state = audio::orchestra::state::closed;
|
||||
m_mode = audio::orchestra::mode_unknow;
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
void audio::orchestra::api::Pulse::callbackEventOneCycle() {
|
||||
if (m_state == audio::orchestra::state::stopped) {
|
||||
while (!m_private->runnable) {
|
||||
m_private->m_semaphore.wait();
|
||||
}
|
||||
if (m_state != audio::orchestra::state::running) {
|
||||
m_mutex.unLock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("the stream is closed ... this shouldn't happen!");
|
||||
return;
|
||||
}
|
||||
audio::Time streamTime = getStreamTime();
|
||||
etk::Vector<enum audio::orchestra::status> status;
|
||||
int32_t doStopStream = m_callback(&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)][0],
|
||||
streamTime,
|
||||
&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0],
|
||||
streamTime,
|
||||
m_bufferSize,
|
||||
status);
|
||||
if (doStopStream == 2) {
|
||||
abortStream();
|
||||
return;
|
||||
}
|
||||
m_mutex.lock();
|
||||
void *pulse_in = m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] ? m_deviceBuffer : &m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)][0];
|
||||
void *pulse_out = m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] ? m_deviceBuffer : &m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0];
|
||||
if (m_state != audio::orchestra::state::running) {
|
||||
goto unLock;
|
||||
}
|
||||
int32_t pa_error;
|
||||
size_t bytes;
|
||||
if (m_mode == audio::orchestra::mode_output) {
|
||||
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)]) {
|
||||
convertBuffer(m_deviceBuffer,
|
||||
&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)][0],
|
||||
m_convertInfo[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)]);
|
||||
bytes = m_nDeviceChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] * m_bufferSize * audio::getFormatBytes(m_deviceFormat[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)]);
|
||||
} else {
|
||||
bytes = m_nUserChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_output)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
}
|
||||
if (pa_simple_write(m_private->handle, pulse_out, bytes, &pa_error) < 0) {
|
||||
ATA_ERROR("audio write error, " << pa_strerror(pa_error) << ".");
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (m_mode == audio::orchestra::mode_input) {
|
||||
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]) {
|
||||
bytes = m_nDeviceChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] * m_bufferSize * audio::getFormatBytes(m_deviceFormat[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]);
|
||||
} else {
|
||||
bytes = m_nUserChannels[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)] * m_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
}
|
||||
if (pa_simple_read(m_private->handle, pulse_in, bytes, &pa_error) < 0) {
|
||||
ATA_ERROR("audio read error, " << pa_strerror(pa_error) << ".");
|
||||
return;
|
||||
}
|
||||
if (m_doConvertBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]) {
|
||||
convertBuffer(&m_userBuffer[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)][0],
|
||||
m_deviceBuffer,
|
||||
m_convertInfo[audio::orchestra::modeToIdTable(audio::orchestra::mode_input)]);
|
||||
}
|
||||
}
|
||||
unLock:
|
||||
m_mutex.unLock();
|
||||
audio::orchestra::Api::tickStreamTime();
|
||||
if (doStopStream == 1) {
|
||||
stopStream();
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Pulse::startStream() {
|
||||
// TODO : Check return ...
|
||||
audio::orchestra::Api::startStream();
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("the stream is not open!");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::running) {
|
||||
ATA_ERROR("the stream is already running!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_mutex.lock();
|
||||
m_state = audio::orchestra::state::running;
|
||||
m_private->runnable = true;
|
||||
m_private->m_semaphore.post();
|
||||
m_mutex.unLock();
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Pulse::stopStream() {
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("the stream is not open!");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
m_mutex.lock();
|
||||
if ( m_private != null
|
||||
&& m_private->handle != null
|
||||
&& m_mode == audio::orchestra::mode_output) {
|
||||
int32_t pa_error;
|
||||
if (pa_simple_drain(m_private->handle, &pa_error) < 0) {
|
||||
ATA_ERROR("error draining output device, " << pa_strerror(pa_error) << ".");
|
||||
m_mutex.unLock();
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
}
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
m_mutex.unLock();
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
enum audio::orchestra::error audio::orchestra::api::Pulse::abortStream() {
|
||||
if (m_state == audio::orchestra::state::closed) {
|
||||
ATA_ERROR("the stream is not open!");
|
||||
return audio::orchestra::error_invalidUse;
|
||||
}
|
||||
if (m_state == audio::orchestra::state::stopped) {
|
||||
ATA_ERROR("the stream is already stopped!");
|
||||
return audio::orchestra::error_warning;
|
||||
}
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
m_mutex.lock();
|
||||
if ( m_private != null
|
||||
&& m_private->handle != null
|
||||
&& m_mode == audio::orchestra::mode_output) {
|
||||
int32_t pa_error;
|
||||
if (pa_simple_flush(m_private->handle, &pa_error) < 0) {
|
||||
ATA_ERROR("error flushing output device, " << pa_strerror(pa_error) << ".");
|
||||
m_mutex.unLock();
|
||||
return audio::orchestra::error_systemError;
|
||||
}
|
||||
}
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
m_mutex.unLock();
|
||||
return audio::orchestra::error_none;
|
||||
}
|
||||
|
||||
bool audio::orchestra::api::Pulse::open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options) {
|
||||
uint64_t bufferBytes = 0;
|
||||
pa_sample_spec ss;
|
||||
if (_device != 0) {
|
||||
return false;
|
||||
}
|
||||
if (_mode != audio::orchestra::mode_input && _mode != audio::orchestra::mode_output) {
|
||||
return false;
|
||||
}
|
||||
if (_channels != 1 && _channels != 2) {
|
||||
ATA_ERROR("unsupported number of channels.");
|
||||
return false;
|
||||
}
|
||||
ss.channels = _channels;
|
||||
if (_firstChannel != 0) {
|
||||
return false;
|
||||
}
|
||||
bool sr_found = false;
|
||||
for (const uint32_t *sr = SUPPORTED_SAMPLERATES; *sr; ++sr) {
|
||||
if (_sampleRate == *sr) {
|
||||
sr_found = true;
|
||||
m_sampleRate = _sampleRate;
|
||||
ss.rate = _sampleRate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sr_found) {
|
||||
ATA_ERROR("unsupported sample rate.");
|
||||
return false;
|
||||
}
|
||||
bool sf_found = 0;
|
||||
for (const rtaudio_pa_format_mapping_t *sf = supported_sampleformats;
|
||||
sf->airtaudio_format && sf->pa_format != PA_SAMPLE_INVALID;
|
||||
++sf) {
|
||||
if (_format == sf->airtaudio_format) {
|
||||
sf_found = true;
|
||||
m_userFormat = sf->airtaudio_format;
|
||||
ss.format = sf->pa_format;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!sf_found) {
|
||||
ATA_ERROR("unsupported sample format.");
|
||||
return false;
|
||||
}
|
||||
m_deviceInterleaved[modeToIdTable(_mode)] = true;
|
||||
m_nBuffers = 1;
|
||||
m_doByteSwap[modeToIdTable(_mode)] = false;
|
||||
m_doConvertBuffer[modeToIdTable(_mode)] = false;
|
||||
m_deviceFormat[modeToIdTable(_mode)] = m_userFormat;
|
||||
m_nUserChannels[modeToIdTable(_mode)] = _channels;
|
||||
m_nDeviceChannels[modeToIdTable(_mode)] = _channels + _firstChannel;
|
||||
m_channelOffset[modeToIdTable(_mode)] = 0;
|
||||
// Allocate necessary internal buffers.
|
||||
bufferBytes = m_nUserChannels[modeToIdTable(_mode)] * *_bufferSize * audio::getFormatBytes(m_userFormat);
|
||||
m_userBuffer[modeToIdTable(_mode)].resize(bufferBytes, 0);
|
||||
if (m_userBuffer[modeToIdTable(_mode)].size() == 0) {
|
||||
ATA_ERROR("error allocating user buffer memory.");
|
||||
goto error;
|
||||
}
|
||||
m_bufferSize = *_bufferSize;
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
bool makeBuffer = true;
|
||||
bufferBytes = m_nDeviceChannels[modeToIdTable(_mode)] * audio::getFormatBytes(m_deviceFormat[modeToIdTable(_mode)]);
|
||||
if (_mode == audio::orchestra::mode_input) {
|
||||
if (m_mode == audio::orchestra::mode_output && m_deviceBuffer) {
|
||||
uint64_t bytesOut = m_nDeviceChannels[0] * audio::getFormatBytes(m_deviceFormat[0]);
|
||||
if (bufferBytes <= bytesOut) makeBuffer = false;
|
||||
}
|
||||
}
|
||||
if (makeBuffer) {
|
||||
bufferBytes *= *_bufferSize;
|
||||
if (m_deviceBuffer) free(m_deviceBuffer);
|
||||
m_deviceBuffer = (char *) calloc(bufferBytes, 1);
|
||||
if (m_deviceBuffer == null) {
|
||||
ATA_ERROR("error allocating device buffer memory.");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_device[modeToIdTable(_mode)] = _device;
|
||||
// Setup the buffer conversion information structure.
|
||||
if (m_doConvertBuffer[modeToIdTable(_mode)]) {
|
||||
setConvertInfo(_mode, _firstChannel);
|
||||
}
|
||||
int32_t error;
|
||||
switch (_mode) {
|
||||
case audio::orchestra::mode_input:
|
||||
m_private->handle = pa_simple_new(null, "orchestra", PA_STREAM_RECORD, null, "Record", &ss, null, null, &error);
|
||||
if (m_private->handle == null) {
|
||||
ATA_ERROR("error connecting input to PulseAudio server.");
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
case audio::orchestra::mode_output:
|
||||
m_private->handle = pa_simple_new(null, "orchestra", PA_STREAM_PLAYBACK, null, "Playback", &ss, null, null, &error);
|
||||
if (m_private->handle == null) {
|
||||
ATA_ERROR("error connecting output to PulseAudio server.");
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
goto error;
|
||||
}
|
||||
if (m_mode == audio::orchestra::mode_unknow) {
|
||||
m_mode = _mode;
|
||||
} else {
|
||||
goto error;
|
||||
}
|
||||
if (m_private->threadRunning == false) {
|
||||
m_private->threadRunning = true;
|
||||
m_private->thread = ememory::makeShared<ethread::Thread>([&](){callbackEvent();}, "pulseCallback");
|
||||
if (m_private->thread == null) {
|
||||
ATA_ERROR("error creating thread.");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
m_state = audio::orchestra::state::stopped;
|
||||
return true;
|
||||
error:
|
||||
for (int32_t iii=0; iii<2; ++iii) {
|
||||
m_userBuffer[iii].clear();
|
||||
}
|
||||
if (m_deviceBuffer) {
|
||||
free(m_deviceBuffer);
|
||||
m_deviceBuffer = 0;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
52
audio/orchestra/api/Pulse.hpp
Normal file
52
audio/orchestra/api/Pulse.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef ORCHESTRA_BUILD_PULSE
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
class PulsePrivate;
|
||||
class Pulse: public audio::orchestra::Api {
|
||||
public:
|
||||
static ememory::SharedPtr<audio::orchestra::Api> create();
|
||||
public:
|
||||
Pulse();
|
||||
virtual ~Pulse();
|
||||
const etk::String& getCurrentApi() {
|
||||
return audio::orchestra::typePulse;
|
||||
}
|
||||
uint32_t getDeviceCount();
|
||||
audio::orchestra::DeviceInfo getDeviceInfo(uint32_t _device);
|
||||
enum audio::orchestra::error closeStream();
|
||||
enum audio::orchestra::error startStream();
|
||||
enum audio::orchestra::error stopStream();
|
||||
enum audio::orchestra::error abortStream();
|
||||
// This function is intended for internal use only. It must be
|
||||
// public because it is called by the internal callback handler,
|
||||
// which is not a member of RtAudio. External use of this function
|
||||
// will most likely produce highly undesireable results!
|
||||
void callbackEventOneCycle();
|
||||
void callbackEvent();
|
||||
private:
|
||||
ememory::SharedPtr<PulsePrivate> m_private;
|
||||
etk::Vector<audio::orchestra::DeviceInfo> m_devices;
|
||||
void saveDeviceInfo();
|
||||
bool open(uint32_t _device,
|
||||
audio::orchestra::mode _mode,
|
||||
uint32_t _channels,
|
||||
uint32_t _firstChannel,
|
||||
uint32_t _sampleRate,
|
||||
audio::format _format,
|
||||
uint32_t *_bufferSize,
|
||||
const audio::orchestra::StreamOptions& _options);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
363
audio/orchestra/api/PulseDeviceList.cpp
Normal file
363
audio/orchestra/api/PulseDeviceList.cpp
Normal file
@ -0,0 +1,363 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#if defined(ORCHESTRA_BUILD_PULSE)
|
||||
extern "C" {
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
}
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <audio/orchestra/api/PulseDeviceList.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
#include <audio/Time.hpp>
|
||||
#include <audio/Duration.hpp>
|
||||
#include <audio/format.hpp>
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
// This callback gets called when our context changes state. We really only
|
||||
// care about when it's ready or if it has failed
|
||||
static void callbackStateMachine(pa_context* _contex, void *_userdata) {
|
||||
pa_context_state_t state;
|
||||
int *pulseAudioReady = static_cast<int*>(_userdata);
|
||||
state = pa_context_get_state(_contex);
|
||||
switch (state) {
|
||||
// There are just here for reference
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
ATA_VERBOSE("pulse state: PA_CONTEXT_UNCONNECTED");
|
||||
break;
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
ATA_VERBOSE("pulse state: PA_CONTEXT_CONNECTING");
|
||||
break;
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
ATA_VERBOSE("pulse state: PA_CONTEXT_AUTHORIZING");
|
||||
break;
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
ATA_VERBOSE("pulse state: PA_CONTEXT_SETTING_NAME");
|
||||
break;
|
||||
default:
|
||||
ATA_VERBOSE("pulse state: default");
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
*pulseAudioReady = 2;
|
||||
ATA_VERBOSE("pulse state: PA_CONTEXT_FAILED");
|
||||
break;
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
*pulseAudioReady = 2;
|
||||
ATA_VERBOSE("pulse state: PA_CONTEXT_TERMINATED");
|
||||
break;
|
||||
case PA_CONTEXT_READY:
|
||||
*pulseAudioReady = 1;
|
||||
ATA_VERBOSE("pulse state: PA_CONTEXT_READY");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static audio::format getFormatFromPulseFormat(enum pa_sample_format _format) {
|
||||
switch (_format) {
|
||||
case PA_SAMPLE_U8:
|
||||
return audio::format_int8;
|
||||
break;
|
||||
case PA_SAMPLE_ALAW:
|
||||
ATA_ERROR("Not supported: uint8_t a-law");
|
||||
return audio::format_unknow;
|
||||
case PA_SAMPLE_ULAW:
|
||||
ATA_ERROR("Not supported: uint8_t mu-law");
|
||||
return audio::format_unknow;
|
||||
case PA_SAMPLE_S16LE:
|
||||
return audio::format_int16;
|
||||
break;
|
||||
case PA_SAMPLE_S16BE:
|
||||
return audio::format_int16;
|
||||
break;
|
||||
case PA_SAMPLE_FLOAT32LE:
|
||||
return audio::format_float;
|
||||
break;
|
||||
case PA_SAMPLE_FLOAT32BE:
|
||||
return audio::format_float;
|
||||
break;
|
||||
case PA_SAMPLE_S32LE:
|
||||
return audio::format_int32;
|
||||
break;
|
||||
case PA_SAMPLE_S32BE:
|
||||
return audio::format_int32;
|
||||
break;
|
||||
case PA_SAMPLE_S24LE:
|
||||
return audio::format_int24;
|
||||
break;
|
||||
case PA_SAMPLE_S24BE:
|
||||
return audio::format_int24;
|
||||
break;
|
||||
case PA_SAMPLE_S24_32LE:
|
||||
return audio::format_int24_on_int32;
|
||||
break;
|
||||
case PA_SAMPLE_S24_32BE:
|
||||
return audio::format_int24_on_int32;
|
||||
break;
|
||||
case PA_SAMPLE_INVALID:
|
||||
case PA_SAMPLE_MAX:
|
||||
ATA_ERROR("Not supported: invalid");
|
||||
return audio::format_unknow;
|
||||
}
|
||||
ATA_ERROR("Not supported: UNKNOW flag...");
|
||||
return audio::format_unknow;
|
||||
}
|
||||
|
||||
static etk::Vector<audio::channel> getChannelOrderFromPulseChannel(const struct pa_channel_map& _map) {
|
||||
etk::Vector<audio::channel> out;
|
||||
|
||||
for (int32_t iii=0; iii<_map.channels; ++iii) {
|
||||
switch(_map.map[iii]) {
|
||||
default:
|
||||
case PA_CHANNEL_POSITION_MAX:
|
||||
case PA_CHANNEL_POSITION_INVALID:
|
||||
out.pushBack(audio::channel_unknow);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_MONO:
|
||||
case PA_CHANNEL_POSITION_FRONT_CENTER:
|
||||
out.pushBack(audio::channel_frontCenter);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_FRONT_LEFT:
|
||||
out.pushBack(audio::channel_frontLeft);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_FRONT_RIGHT:
|
||||
out.pushBack(audio::channel_frontRight);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_REAR_CENTER:
|
||||
out.pushBack(audio::channel_rearCenter);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_REAR_LEFT:
|
||||
out.pushBack(audio::channel_rearLeft);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_REAR_RIGHT:
|
||||
out.pushBack(audio::channel_rearRight);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_LFE:
|
||||
out.pushBack(audio::channel_lfe);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER:
|
||||
out.pushBack(audio::channel_centerLeft);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER:
|
||||
out.pushBack(audio::channel_centerRight);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_SIDE_LEFT:
|
||||
out.pushBack(audio::channel_topCenterLeft);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_SIDE_RIGHT:
|
||||
out.pushBack(audio::channel_topCenterRight);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_TOP_CENTER:
|
||||
case PA_CHANNEL_POSITION_TOP_FRONT_CENTER:
|
||||
out.pushBack(audio::channel_topFrontCenter);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_TOP_FRONT_LEFT:
|
||||
out.pushBack(audio::channel_topFrontLeft);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_TOP_FRONT_RIGHT:
|
||||
out.pushBack(audio::channel_topFrontRight);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_TOP_REAR_LEFT:
|
||||
out.pushBack(audio::channel_topRearLeft);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_TOP_REAR_RIGHT:
|
||||
out.pushBack(audio::channel_topRearRight);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_TOP_REAR_CENTER:
|
||||
out.pushBack(audio::channel_topRearCenter);
|
||||
break;
|
||||
case PA_CHANNEL_POSITION_AUX0: out.pushBack(audio::channel_aux0); break;
|
||||
case PA_CHANNEL_POSITION_AUX1: out.pushBack(audio::channel_aux1); break;
|
||||
case PA_CHANNEL_POSITION_AUX2: out.pushBack(audio::channel_aux2); break;
|
||||
case PA_CHANNEL_POSITION_AUX3: out.pushBack(audio::channel_aux3); break;
|
||||
case PA_CHANNEL_POSITION_AUX4: out.pushBack(audio::channel_aux4); break;
|
||||
case PA_CHANNEL_POSITION_AUX5: out.pushBack(audio::channel_aux5); break;
|
||||
case PA_CHANNEL_POSITION_AUX6: out.pushBack(audio::channel_aux6); break;
|
||||
case PA_CHANNEL_POSITION_AUX7: out.pushBack(audio::channel_aux7); break;
|
||||
case PA_CHANNEL_POSITION_AUX8: out.pushBack(audio::channel_aux8); break;
|
||||
case PA_CHANNEL_POSITION_AUX9: out.pushBack(audio::channel_aux9); break;
|
||||
case PA_CHANNEL_POSITION_AUX10: out.pushBack(audio::channel_aux10); break;
|
||||
case PA_CHANNEL_POSITION_AUX11: out.pushBack(audio::channel_aux11); break;
|
||||
case PA_CHANNEL_POSITION_AUX12: out.pushBack(audio::channel_aux12); break;
|
||||
case PA_CHANNEL_POSITION_AUX13: out.pushBack(audio::channel_aux13); break;
|
||||
case PA_CHANNEL_POSITION_AUX14: out.pushBack(audio::channel_aux14); break;
|
||||
case PA_CHANNEL_POSITION_AUX15: out.pushBack(audio::channel_aux15); break;
|
||||
case PA_CHANNEL_POSITION_AUX16: out.pushBack(audio::channel_aux16); break;
|
||||
case PA_CHANNEL_POSITION_AUX17: out.pushBack(audio::channel_aux17); break;
|
||||
case PA_CHANNEL_POSITION_AUX18: out.pushBack(audio::channel_aux18); break;
|
||||
case PA_CHANNEL_POSITION_AUX19: out.pushBack(audio::channel_aux19); break;
|
||||
case PA_CHANNEL_POSITION_AUX20: out.pushBack(audio::channel_aux20); break;
|
||||
case PA_CHANNEL_POSITION_AUX21: out.pushBack(audio::channel_aux21); break;
|
||||
case PA_CHANNEL_POSITION_AUX22: out.pushBack(audio::channel_aux22); break;
|
||||
case PA_CHANNEL_POSITION_AUX23: out.pushBack(audio::channel_aux23); break;
|
||||
case PA_CHANNEL_POSITION_AUX24: out.pushBack(audio::channel_aux24); break;
|
||||
case PA_CHANNEL_POSITION_AUX25: out.pushBack(audio::channel_aux25); break;
|
||||
case PA_CHANNEL_POSITION_AUX26: out.pushBack(audio::channel_aux26); break;
|
||||
case PA_CHANNEL_POSITION_AUX27: out.pushBack(audio::channel_aux27); break;
|
||||
case PA_CHANNEL_POSITION_AUX28: out.pushBack(audio::channel_aux28); break;
|
||||
case PA_CHANNEL_POSITION_AUX29: out.pushBack(audio::channel_aux29); break;
|
||||
case PA_CHANNEL_POSITION_AUX30: out.pushBack(audio::channel_aux30); break;
|
||||
case PA_CHANNEL_POSITION_AUX31: out.pushBack(audio::channel_aux31); break;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
// Callback on getting data from pulseaudio:
|
||||
static void callbackGetSinkList(pa_context* _contex, const pa_sink_info* _info, int _eol, void* _userdata) {
|
||||
etk::Vector<audio::orchestra::DeviceInfo>* list = static_cast<etk::Vector<audio::orchestra::DeviceInfo>*>(_userdata);
|
||||
// If eol is set to a positive number, you're at the end of the list
|
||||
if (_eol > 0) {
|
||||
return;
|
||||
}
|
||||
audio::orchestra::DeviceInfo info;
|
||||
info.isCorrect = true;
|
||||
info.input = false;
|
||||
info.name = _info->name;
|
||||
info.desc = _info->description;
|
||||
info.sampleRates.pushBack(_info->sample_spec.rate);
|
||||
info.nativeFormats.pushBack(getFormatFromPulseFormat(_info->sample_spec.format));
|
||||
info.channels = getChannelOrderFromPulseChannel(_info->channel_map);
|
||||
ATA_VERBOSE("plop=" << _info->index << " " << _info->name);
|
||||
//ATA_DEBUG(" ports=" << _info->n_ports);
|
||||
list->pushBack(info);
|
||||
}
|
||||
|
||||
// allback to get data from pulseaudio:
|
||||
static void callbackGetSourceList(pa_context* _contex, const pa_source_info* _info, int _eol, void* _userdata) {
|
||||
etk::Vector<audio::orchestra::DeviceInfo>* list = static_cast<etk::Vector<audio::orchestra::DeviceInfo>*>(_userdata);
|
||||
if (_eol > 0) {
|
||||
return;
|
||||
}
|
||||
audio::orchestra::DeviceInfo info;
|
||||
info.isCorrect = true;
|
||||
info.input = true;
|
||||
info.name = _info->name;
|
||||
info.desc = _info->description;
|
||||
info.sampleRates.pushBack(_info->sample_spec.rate);
|
||||
info.nativeFormats.pushBack(getFormatFromPulseFormat(_info->sample_spec.format));
|
||||
info.channels = getChannelOrderFromPulseChannel(_info->channel_map);
|
||||
ATA_VERBOSE("plop=" << _info->index << " " << _info->name);
|
||||
list->pushBack(info);
|
||||
}
|
||||
|
||||
// to not update all the time ...
|
||||
static etk::Vector<audio::orchestra::DeviceInfo> pulseAudioListOfDevice;
|
||||
static audio::Time pulseAudioListOfDeviceTime;
|
||||
|
||||
etk::Vector<audio::orchestra::DeviceInfo> audio::orchestra::api::pulse::getDeviceList() {
|
||||
audio::Duration delta = audio::Time::now() - pulseAudioListOfDeviceTime;
|
||||
if (delta < audio::Duration(30,0)) {
|
||||
return pulseAudioListOfDevice;
|
||||
}
|
||||
// Define our pulse audio loop and connection variables
|
||||
pa_mainloop* pulseAudioMainLoop;
|
||||
pa_mainloop_api* pulseAudioMainLoopAPI;
|
||||
pa_operation* pulseAudioOperation;
|
||||
pa_context* pulseAudioContex;
|
||||
pa_context_flags_t pulseAudioFlags = PA_CONTEXT_NOAUTOSPAWN;
|
||||
etk::Vector<audio::orchestra::DeviceInfo>& out = pulseAudioListOfDevice;
|
||||
out.clear();
|
||||
// We'll need these state variables to keep track of our requests
|
||||
int state = 0;
|
||||
int pulseAudioReady = 0;
|
||||
// Create a mainloop API and connection to the default server
|
||||
pulseAudioMainLoop = pa_mainloop_new();
|
||||
pulseAudioMainLoopAPI = pa_mainloop_get_api(pulseAudioMainLoop);
|
||||
pulseAudioContex = pa_context_new(pulseAudioMainLoopAPI, "orchestraPulseCount");
|
||||
// If there's an error, the callback will set pulseAudioReady
|
||||
pa_context_set_state_callback(pulseAudioContex, callbackStateMachine, &pulseAudioReady);
|
||||
// This function connects to the pulse server
|
||||
pa_context_connect(pulseAudioContex, NULL, pulseAudioFlags, NULL);
|
||||
bool playLoop = true;
|
||||
while (playLoop == true) {
|
||||
// We can't do anything until PA is ready, so just iterate the mainloop
|
||||
// and continue
|
||||
if (pulseAudioReady == 0) {
|
||||
pa_mainloop_iterate(pulseAudioMainLoop, 1, null);
|
||||
continue;
|
||||
}
|
||||
// We couldn't get a connection to the server, so exit out
|
||||
if (pulseAudioReady == 2) {
|
||||
pa_context_disconnect(pulseAudioContex);
|
||||
pa_context_unref(pulseAudioContex);
|
||||
pa_mainloop_free(pulseAudioMainLoop);
|
||||
ATA_ERROR("Pulse interface error: Can not connect to the pulseaudio iterface...");
|
||||
return out;
|
||||
}
|
||||
// At this point, we're connected to the server and ready to make
|
||||
// requests
|
||||
switch (state) {
|
||||
// State 0: we haven't done anything yet
|
||||
case 0:
|
||||
ATA_DEBUG("Request sink list");
|
||||
pulseAudioOperation = pa_context_get_sink_info_list(pulseAudioContex,
|
||||
callbackGetSinkList,
|
||||
&out);
|
||||
state++;
|
||||
break;
|
||||
case 1:
|
||||
// Now we wait for our operation to complete. When it's
|
||||
// complete our pa_output_devicelist is filled out, and we move
|
||||
// along to the next state
|
||||
if (pa_operation_get_state(pulseAudioOperation) == PA_OPERATION_DONE) {
|
||||
pa_operation_unref(pulseAudioOperation);
|
||||
ATA_DEBUG("Request sources list");
|
||||
pulseAudioOperation = pa_context_get_source_info_list(pulseAudioContex,
|
||||
callbackGetSourceList,
|
||||
&out);
|
||||
state++;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (pa_operation_get_state(pulseAudioOperation) == PA_OPERATION_DONE) {
|
||||
ATA_DEBUG("All is done");
|
||||
// Now we're done, clean up and disconnect and return
|
||||
pa_operation_unref(pulseAudioOperation);
|
||||
pa_context_disconnect(pulseAudioContex);
|
||||
pa_context_unref(pulseAudioContex);
|
||||
pa_mainloop_free(pulseAudioMainLoop);
|
||||
playLoop = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// We should never see this state
|
||||
ATA_ERROR("Error in getting the devices list ...");
|
||||
return out;
|
||||
}
|
||||
// Iterate the main loop ..
|
||||
if (playLoop == true) {
|
||||
pa_mainloop_iterate(pulseAudioMainLoop, 1, null);
|
||||
}
|
||||
}
|
||||
// TODO: need to do it better ...
|
||||
// set default device:
|
||||
int32_t idInput = -1;
|
||||
int32_t idOutput = -1;
|
||||
for (int32_t iii=0; iii<out.size(); ++iii) {
|
||||
if (out[iii].input == true) {
|
||||
if (idInput != -1) {
|
||||
continue;
|
||||
}
|
||||
if (etk::end_with(out[iii].name, ".monitor", false) == false) {
|
||||
idInput = iii;
|
||||
out[iii].isDefault = true;
|
||||
}
|
||||
} else {
|
||||
if (idOutput != -1) {
|
||||
continue;
|
||||
}
|
||||
if (etk::end_with(out[iii].name, ".monitor", false) == false) {
|
||||
idOutput = iii;
|
||||
out[iii].isDefault = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
#endif
|
23
audio/orchestra/api/PulseDeviceList.hpp
Normal file
23
audio/orchestra/api/PulseDeviceList.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
#ifdef ORCHESTRA_BUILD_PULSE
|
||||
|
||||
#include <etk/types.hpp>
|
||||
#include <audio/orchestra/DeviceInfo.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
namespace api {
|
||||
namespace pulse {
|
||||
etk::Vector<audio::orchestra::DeviceInfo> getDeviceList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
6
audio/orchestra/base.cpp
Normal file
6
audio/orchestra/base.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
25
audio/orchestra/base.hpp
Normal file
25
audio/orchestra/base.hpp
Normal file
@ -0,0 +1,25 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <ethread/Thread.hpp>
|
||||
#include <ethread/Semaphore.hpp>
|
||||
#include <ethread/Mutex.hpp>
|
||||
#include <echrono/Steady.hpp>
|
||||
#include <etk/Function.hpp>
|
||||
#include <ememory/memory.hpp>
|
||||
#include <audio/channel.hpp>
|
||||
#include <audio/format.hpp>
|
||||
#include <audio/orchestra/error.hpp>
|
||||
#include <audio/orchestra/status.hpp>
|
||||
#include <audio/orchestra/Flags.hpp>
|
||||
|
||||
#include <audio/orchestra/CallbackInfo.hpp>
|
||||
#include <audio/orchestra/DeviceInfo.hpp>
|
||||
#include <audio/orchestra/StreamOptions.hpp>
|
||||
#include <audio/orchestra/StreamParameters.hpp>
|
||||
|
13
audio/orchestra/debug.cpp
Normal file
13
audio/orchestra/debug.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
|
||||
int32_t audio::orchestra::getLogId() {
|
||||
static int32_t g_val = elog::registerInstance("audio-orchestra");
|
||||
return g_val;
|
||||
}
|
41
audio/orchestra/debug.hpp
Normal file
41
audio/orchestra/debug.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <elog/log.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
int32_t getLogId();
|
||||
}
|
||||
}
|
||||
#define ATA_BASE(info,data) ELOG_BASE(audio::orchestra::getLogId(),info,data)
|
||||
|
||||
#define ATA_PRINT(data) ATA_BASE(-1, data)
|
||||
#define ATA_CRITICAL(data) ATA_BASE(1, data)
|
||||
#define ATA_ERROR(data) ATA_BASE(2, data)
|
||||
#define ATA_WARNING(data) ATA_BASE(3, data)
|
||||
#ifdef DEBUG
|
||||
#define ATA_INFO(data) ATA_BASE(4, data)
|
||||
#define ATA_DEBUG(data) ATA_BASE(5, data)
|
||||
#define ATA_VERBOSE(data) ATA_BASE(6, data)
|
||||
#define ATA_TODO(data) ATA_BASE(4, "TODO : " << data)
|
||||
#else
|
||||
#define ATA_INFO(data) do { } while(false)
|
||||
#define ATA_DEBUG(data) do { } while(false)
|
||||
#define ATA_VERBOSE(data) do { } while(false)
|
||||
#define ATA_TODO(data) do { } while(false)
|
||||
#endif
|
||||
|
||||
#define ATA_ASSERT(cond,data) \
|
||||
do { \
|
||||
if (!(cond)) { \
|
||||
ATA_CRITICAL(data); \
|
||||
assert(!#cond); \
|
||||
} \
|
||||
} while (0)
|
||||
|
9
audio/orchestra/error.cpp
Normal file
9
audio/orchestra/error.cpp
Normal file
@ -0,0 +1,9 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <audio/orchestra/error.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
22
audio/orchestra/error.hpp
Normal file
22
audio/orchestra/error.hpp
Normal file
@ -0,0 +1,22 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum error {
|
||||
error_none, //!< No error
|
||||
error_fail, //!< An error occure in the operation
|
||||
error_warning, //!< A non-critical error.
|
||||
error_inputNull, //!< null input or internal errror
|
||||
error_invalidUse, //!< The function was called incorrectly.
|
||||
error_systemError //!< A system error occured.
|
||||
};
|
||||
}
|
||||
}
|
39
audio/orchestra/mode.cpp
Normal file
39
audio/orchestra/mode.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <audio/orchestra/mode.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
|
||||
int32_t audio::orchestra::modeToIdTable(enum mode _mode) {
|
||||
switch (_mode) {
|
||||
case mode_unknow:
|
||||
case mode_duplex:
|
||||
case mode_output:
|
||||
return 0;
|
||||
case mode_input:
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
etk::Stream& audio::operator <<(etk::Stream& _os, enum audio::orchestra::mode _obj) {
|
||||
switch (_obj) {
|
||||
case audio::orchestra::mode_unknow:
|
||||
_os << "unknow";
|
||||
break;
|
||||
case audio::orchestra::mode_duplex:
|
||||
_os << "duplex";
|
||||
break;
|
||||
case audio::orchestra::mode_output:
|
||||
_os << "output";
|
||||
break;
|
||||
case audio::orchestra::mode_input:
|
||||
_os << "input";
|
||||
break;
|
||||
}
|
||||
return _os;
|
||||
}
|
24
audio/orchestra/mode.hpp
Normal file
24
audio/orchestra/mode.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.hpp>
|
||||
#include <etk/Stream.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum mode {
|
||||
mode_unknow,
|
||||
mode_output,
|
||||
mode_input,
|
||||
mode_duplex
|
||||
};
|
||||
int32_t modeToIdTable(enum mode _mode);
|
||||
}
|
||||
etk::Stream& operator <<(etk::Stream& _os, enum audio::orchestra::mode _obj);
|
||||
}
|
||||
|
6
audio/orchestra/state.cpp
Normal file
6
audio/orchestra/state.cpp
Normal file
@ -0,0 +1,6 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
21
audio/orchestra/state.hpp
Normal file
21
audio/orchestra/state.hpp
Normal file
@ -0,0 +1,21 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum class state {
|
||||
closed,
|
||||
stopped,
|
||||
stopping,
|
||||
running
|
||||
};
|
||||
}
|
||||
}
|
||||
|
32
audio/orchestra/status.cpp
Normal file
32
audio/orchestra/status.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <audio/orchestra/status.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
static const char* listValue[] = {
|
||||
"ok",
|
||||
"overflow",
|
||||
"underflow"
|
||||
};
|
||||
|
||||
etk::Stream& audio::orchestra::operator <<(etk::Stream& _os, enum audio::orchestra::status _obj) {
|
||||
_os << listValue[int32_t(_obj)];
|
||||
return _os;
|
||||
}
|
||||
|
||||
etk::Stream& audio::orchestra::operator <<(etk::Stream& _os, const etk::Vector<enum audio::orchestra::status>& _obj) {
|
||||
_os << etk::String("{");
|
||||
for (size_t iii=0; iii<_obj.size(); ++iii) {
|
||||
if (iii!=0) {
|
||||
_os << etk::String(";");
|
||||
}
|
||||
_os << _obj[iii];
|
||||
}
|
||||
_os << etk::String("}");
|
||||
return _os;
|
||||
}
|
||||
|
23
audio/orchestra/status.hpp
Normal file
23
audio/orchestra/status.hpp
Normal file
@ -0,0 +1,23 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.hpp>
|
||||
#include <etk/Vector.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
enum class status {
|
||||
ok, //!< nothing...
|
||||
overflow, //!< Internal buffer has more data than they can accept
|
||||
underflow //!< The internal buffer is empty
|
||||
};
|
||||
etk::Stream& operator <<(etk::Stream& _os, enum audio::orchestra::status _obj);
|
||||
etk::Stream& operator <<(etk::Stream& _os, const etk::Vector<enum audio::orchestra::status>& _obj);
|
||||
}
|
||||
}
|
||||
|
21
audio/orchestra/type.cpp
Normal file
21
audio/orchestra/type.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
|
||||
#include <audio/orchestra/type.hpp>
|
||||
#include <audio/orchestra/debug.hpp>
|
||||
|
||||
const etk::String audio::orchestra::typeUndefined = "undefined";
|
||||
const etk::String audio::orchestra::typeAlsa = "alsa";
|
||||
const etk::String audio::orchestra::typePulse = "pulse";
|
||||
const etk::String audio::orchestra::typeOss = "oss";
|
||||
const etk::String audio::orchestra::typeJack = "jack";
|
||||
const etk::String audio::orchestra::typeCoreOSX = "coreOSX";
|
||||
const etk::String audio::orchestra::typeCoreIOS = "coreIOS";
|
||||
const etk::String audio::orchestra::typeAsio = "asio";
|
||||
const etk::String audio::orchestra::typeDs = "ds";
|
||||
const etk::String audio::orchestra::typeJava = "java";
|
||||
const etk::String audio::orchestra::typeDummy = "dummy";
|
30
audio/orchestra/type.hpp
Normal file
30
audio/orchestra/type.hpp
Normal file
@ -0,0 +1,30 @@
|
||||
/** @file
|
||||
* @author Edouard DUPIN
|
||||
* @copyright 2011, Edouard DUPIN, all right reserved
|
||||
* @license APACHE v2.0 (see license file)
|
||||
* @fork from RTAudio
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <etk/types.hpp>
|
||||
#include <etk/stdTools.hpp>
|
||||
|
||||
namespace audio {
|
||||
namespace orchestra {
|
||||
/**
|
||||
* @brief Audio API specifier arguments.
|
||||
*/
|
||||
extern const etk::String typeUndefined; //!< Error API.
|
||||
extern const etk::String typeAlsa; //!< LINUX The Advanced Linux Sound Architecture.
|
||||
extern const etk::String typePulse; //!< LINUX The Linux PulseAudio.
|
||||
extern const etk::String typeOss; //!< LINUX The Linux Open Sound System.
|
||||
extern const etk::String typeJack; //!< UNIX The Jack Low-Latency Audio Server.
|
||||
extern const etk::String typeCoreOSX; //!< Macintosh OSX Core Audio.
|
||||
extern const etk::String typeCoreIOS; //!< Macintosh iOS Core Audio.
|
||||
extern const etk::String typeAsio; //!< WINDOWS The Steinberg Audio Stream I/O.
|
||||
extern const etk::String typeDs; //!< WINDOWS The Microsoft Direct Sound.
|
||||
extern const etk::String typeJava; //!< ANDROID Interface.
|
||||
extern const etk::String typeDummy; //!< Empty wrapper (non-functional).
|
||||
}
|
||||
}
|
||||
|
@ -1,184 +0,0 @@
|
||||
<!-- HTML header for doxygen 1.8.8-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- For Mobile Devices -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
|
||||
<title>Orchestra: audio interface wrapper: Build lib & build sample</title>
|
||||
<!--<link href="tabs.css" rel="stylesheet" type="text/css"/>-->
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="search/searchdata.js"></script>
|
||||
<script type="text/javascript" src="search/search.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="customdoxygen.css" rel="stylesheet" type="text/css"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="doxy-boot.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand">Orchestra: audio interface wrapper 0.4.0</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="index.html">Main Page</a></li>
|
||||
<li><a href="pages.html">Related Pages</a></li>
|
||||
<li><a href="namespaces.html">Namespaces</a></li>
|
||||
<li><a href="annotated.html">Classes</a></li>
|
||||
<li><a href="files.html">Files</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
Link-libs<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://HeeroYui.github.io/lutin">lutin</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ewol">ewol</a></li>
|
||||
<li><a href="http://atria-soft.github.io/echrono">echrono</a></li>
|
||||
<li><a href="http://atria-soft.github.io/etk">etk</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ejson">ejson</a></li>
|
||||
<li><a href="http://atria-soft.github.io/exml">exml</a></li>
|
||||
<li><a href="http://atria-soft.github.io/esvg">esvg</a></li>
|
||||
<li><a href="http://atria-soft.github.io/egami">egami</a></li>
|
||||
<li><a href="http://atria-soft.github.io/gale">gale</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ege">ege</a></li>
|
||||
<li><a href="http://atria-soft.github.io/elog">elog</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ememory">ememory</a></li>
|
||||
<li><a href="http://atria-soft.github.io/enet">enet</a></li>
|
||||
<li><a href="http://atria-soft.github.io/eproperty">eproperty</a></li>
|
||||
<li><a href="http://atria-soft.github.io/esignal">esignal</a></li>
|
||||
<li><a href="http://atria-soft.github.io/etranslate">etranslate</a></li>
|
||||
<li><a href="http://atria-soft.github.io/zeus">zeus</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-ess">audio-ess</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio">audio</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-drain">audio-drain</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-orchestra">audio-orchestra</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-river">audio-river</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="search-box" class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button aria-expanded="false" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-search"></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#">All</a></li>
|
||||
<li><a href="#">Classes</a></li>
|
||||
<li><a href="#">Namespaces</a></li>
|
||||
<li><a href="#">Files</a></li>
|
||||
<li><a href="#">Functions</a></li>
|
||||
<li><a href="#">Variables</a></li>
|
||||
<li><a href="#">Typedefs</a></li>
|
||||
<li><a href="#">Enumerations</a></li>
|
||||
<li><a href="#">Enumerator</a></li>
|
||||
<li><a href="#">Friends</a></li>
|
||||
<li><a href="#">Macros</a></li>
|
||||
<li><a href="#">Pages</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button id="search-close" type="button" class="close" aria-label="Close">
|
||||
<span aria-hidden="true"></span>
|
||||
</button>
|
||||
<input id="search-field" class="form-control" accesskey="S" onkeydown="searchBox.OnSearchFieldChange(event);" placeholder="Search ..." type="text">
|
||||
</div>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</nav>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div class="content" id="content">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 panel panel-default" style="padding-bottom: 15px;">
|
||||
<div style="margin-bottom: 15px;margin-top: 60px;">
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.12 -->
|
||||
<script type="text/javascript">
|
||||
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||||
</script>
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',true,false,'search.php','Search');
|
||||
$(document).ready(function() { init_search(); });
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
<!-- window showing the filter options -->
|
||||
<div id="MSearchSelectWindow"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||||
</div>
|
||||
|
||||
<!-- iframe showing the search results (closed by default) -->
|
||||
<div id="MSearchResultsWindow">
|
||||
<iframe src="javascript:void(0)" frameborder="0"
|
||||
name="MSearchResults" id="MSearchResults">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
</div><!-- top -->
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">Build lib & build sample </div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="toc"><h3>Table of Contents</h3>
|
||||
<ul><li class="level1"><a href="#audio_orchestra_build_download">Download: </a><ul><li class="level2"><a href="#audio_orchestra_build_download_repo">need google repo: </a></li>
|
||||
<li class="level2"><a href="#audio_orchestra_build_download_lutin">lutin (build-system): </a></li>
|
||||
<li class="level2"><a href="#audio_orchestra_build_download_dependency">dependency: </a></li>
|
||||
<li class="level2"><a href="#audio_orchestra_build_download_sources">sources: </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="level1"><a href="#audio_orchestra_build_build">Build: </a><ul><li class="level2"><a href="#audio_orchestra_build_build_library">library: </a></li>
|
||||
<li class="level2"><a href="#audio_orchestra_build_build_sample">Sample: </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="textblock"><h1><a class="anchor" id="audio_orchestra_build_download"></a>
|
||||
Download: </h1>
|
||||
<p>ege use some tools to manage source and build it:</p>
|
||||
<h2><a class="anchor" id="audio_orchestra_build_download_repo"></a>
|
||||
need google repo: </h2>
|
||||
<p>see: <a href="http://source.android.com/source/downloading.html#installing-repo">http://source.android.com/source/downloading.html#installing-repo</a></p>
|
||||
<p>On all platform: </p><div class="fragment"><div class="line">mkdir ~/.bin</div><div class="line">PATH=~/.bin:$PATH</div><div class="line">curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo</div><div class="line">chmod a+x ~/.bin/repo</div></div><!-- fragment --><p>On ubuntu </p><div class="fragment"><div class="line">sudo apt-get install repo</div></div><!-- fragment --><p>On archlinux </p><div class="fragment"><div class="line">sudo pacman -S repo</div></div><!-- fragment --><h2><a class="anchor" id="audio_orchestra_build_download_lutin"></a>
|
||||
lutin (build-system): </h2>
|
||||
<div class="fragment"><div class="line">pip install lutin --user</div><div class="line"># optionnal dependency of lutin (manage image changing size for application release)</div><div class="line">pip install pillow --user</div></div><!-- fragment --><h2><a class="anchor" id="audio_orchestra_build_download_dependency"></a>
|
||||
dependency: </h2>
|
||||
<div class="fragment"><div class="line">mkdir -p WORKING_DIRECTORY/framework</div><div class="line">cd WORKING_DIRECTORY/framework</div><div class="line">repo init -u git://github.com/atria-soft/manifest.git</div><div class="line">repo sync -j8</div><div class="line">cd ../..</div></div><!-- fragment --><h2><a class="anchor" id="audio_orchestra_build_download_sources"></a>
|
||||
sources: </h2>
|
||||
<p>They are already download in the repo manifest in:</p>
|
||||
<div class="fragment"><div class="line">cd WORKING_DIRECTORY/framework/atria-soft/audio_orchestra</div></div><!-- fragment --><h1><a class="anchor" id="audio_orchestra_build_build"></a>
|
||||
Build: </h1>
|
||||
<p>you must stay in zour working directory... </p><div class="fragment"><div class="line">cd WORKING_DIRECTORY</div></div><!-- fragment --><h2><a class="anchor" id="audio_orchestra_build_build_library"></a>
|
||||
library: </h2>
|
||||
<div class="fragment"><div class="line">lutin -mdebug audio-orchestra</div></div><!-- fragment --><h2><a class="anchor" id="audio_orchestra_build_build_sample"></a>
|
||||
Sample: </h2>
|
||||
<p>No smaple availlable for now ... </p>
|
||||
</div></div><!-- contents -->
|
||||
<!-- HTML footer for doxygen 1.8.8-->
|
||||
<!-- start footer part -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated on Mon Oct 24 2016 15:35:48 for Orchestra: audio interface wrapper by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.12
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
1
authors.txt
Normal file
1
authors.txt
Normal file
@ -0,0 +1 @@
|
||||
MR Edouard DUPIN <yui.heero@gmail.com>
|
BIN
closed.png
BIN
closed.png
Binary file not shown.
Before Width: | Height: | Size: 132 B |
@ -1,377 +0,0 @@
|
||||
|
||||
#navrow1, #navrow2, #navrow3, #navrow4, #navrow5{
|
||||
border-bottom: 1px solid #EEEEEE;
|
||||
}
|
||||
|
||||
.adjust-right {
|
||||
margin-left: 30px !important;
|
||||
font-size: 1.15em !important;
|
||||
}
|
||||
.navbar{
|
||||
border: 0px solid #222 !important;
|
||||
}
|
||||
|
||||
|
||||
/* Sticky footer styles
|
||||
-------------------------------------------------- */
|
||||
html,
|
||||
body {
|
||||
counter-reset: h1counter;
|
||||
height: 100%;
|
||||
/* The html and body elements cannot have any padding or margin. */
|
||||
}
|
||||
h1, .h1, h2, .h2, h3, .h3{
|
||||
font-weight: bold !important;
|
||||
}
|
||||
h1:before {
|
||||
content: counter(h1counter) ".\0000a0\0000a0";
|
||||
counter-increment: h1counter;
|
||||
counter-reset: h2counter;
|
||||
}
|
||||
h2:before {
|
||||
content: counter(h1counter) "." counter(h2counter) ".\0000a0\0000a0";
|
||||
counter-increment: h2counter;
|
||||
counter-reset: h3counter;
|
||||
}
|
||||
h3:before {
|
||||
content: counter(h1counter) "." counter(h2counter) "." counter(h3counter) ".\0000a0\0000a0";
|
||||
counter-increment: h3counter;
|
||||
}
|
||||
|
||||
/* Wrapper for page content to push down footer */
|
||||
#wrap {
|
||||
min-height: 100%;
|
||||
height: auto;
|
||||
/* Negative indent footer by its height */
|
||||
margin: 0 auto -60px;
|
||||
/* Pad bottom by footer height */
|
||||
padding: 0 0 60px;
|
||||
}
|
||||
|
||||
/* Set the fixed height of the footer here */
|
||||
#footer {
|
||||
font-size: 0.9em;
|
||||
padding: 8px 0px;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
.footer-row {
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
#footer > .container {
|
||||
padding-left: 15px;
|
||||
padding-right: 15px;
|
||||
}
|
||||
|
||||
.footer-follow-icon {
|
||||
margin-left: 3px;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.footer-follow-icon img {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.footer-link {
|
||||
padding-top: 5px;
|
||||
display: inline-block;
|
||||
color: #999999;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.footer-copyright {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.footer-row {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.footer-icons {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
@media (max-width: 991px) {
|
||||
.footer-row {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer-icons {
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
/* DOXYGEN Code Styles
|
||||
----------------------------------- */
|
||||
|
||||
|
||||
a.qindex {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
a.qindexHL {
|
||||
font-weight: bold;
|
||||
background-color: #9CAFD4;
|
||||
color: #ffffff;
|
||||
border: 1px double #869DCA;
|
||||
}
|
||||
|
||||
.contents a.qindexHL:visited {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
a.code, a.code:visited, a.line, a.line:visited {
|
||||
color: #4665A2;
|
||||
}
|
||||
|
||||
a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
|
||||
color: #4665A2;
|
||||
}
|
||||
|
||||
/* @end */
|
||||
|
||||
dl.el {
|
||||
margin-left: -1cm;
|
||||
}
|
||||
|
||||
pre.fragment {
|
||||
border: 1px solid #C4CFE5;
|
||||
background-color: #FBFCFD;
|
||||
padding: 4px 6px;
|
||||
margin: 4px 8px 4px 2px;
|
||||
overflow: auto;
|
||||
word-wrap: break-word;
|
||||
font-size: 9pt;
|
||||
line-height: 125%;
|
||||
font-family: monospace, fixed;
|
||||
font-size: 105%;
|
||||
}
|
||||
|
||||
div.fragment {
|
||||
padding: 4px 6px;
|
||||
margin: 4px 8px 4px 2px;
|
||||
border: 1px solid #C4CFE5;
|
||||
}
|
||||
|
||||
div.line {
|
||||
font-family: monospace, fixed;
|
||||
font-size: 13px;
|
||||
min-height: 13px;
|
||||
line-height: 1.0;
|
||||
text-wrap: unrestricted;
|
||||
white-space: -moz-pre-wrap; /* Moz */
|
||||
white-space: -pre-wrap; /* Opera 4-6 */
|
||||
white-space: -o-pre-wrap; /* Opera 7 */
|
||||
white-space: pre-wrap; /* CSS3 */
|
||||
word-wrap: break-word; /* IE 5.5+ */
|
||||
text-indent: -53px;
|
||||
padding-left: 53px;
|
||||
padding-bottom: 0px;
|
||||
margin: 0px;
|
||||
-webkit-transition-property: background-color, box-shadow;
|
||||
-webkit-transition-duration: 0.5s;
|
||||
-moz-transition-property: background-color, box-shadow;
|
||||
-moz-transition-duration: 0.5s;
|
||||
-ms-transition-property: background-color, box-shadow;
|
||||
-ms-transition-duration: 0.5s;
|
||||
-o-transition-property: background-color, box-shadow;
|
||||
-o-transition-duration: 0.5s;
|
||||
transition-property: background-color, box-shadow;
|
||||
transition-duration: 0.5s;
|
||||
}
|
||||
|
||||
div.line.glow {
|
||||
background-color: cyan;
|
||||
box-shadow: 0 0 10px cyan;
|
||||
}
|
||||
|
||||
|
||||
span.lineno {
|
||||
padding-right: 4px;
|
||||
text-align: right;
|
||||
border-right: 2px solid #0F0;
|
||||
background-color: #E8E8E8;
|
||||
white-space: pre;
|
||||
}
|
||||
span.lineno a {
|
||||
background-color: #D8D8D8;
|
||||
}
|
||||
|
||||
span.lineno a:hover {
|
||||
background-color: #C8C8C8;
|
||||
}
|
||||
|
||||
div.groupHeader {
|
||||
margin-left: 16px;
|
||||
margin-top: 12px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
div.groupText {
|
||||
margin-left: 16px;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* @group Code Colorization */
|
||||
|
||||
span.keyword {
|
||||
color: #008000
|
||||
}
|
||||
|
||||
span.keywordtype {
|
||||
color: #604020
|
||||
}
|
||||
|
||||
span.keywordflow {
|
||||
color: #e08000
|
||||
}
|
||||
|
||||
span.comment {
|
||||
color: #800000
|
||||
}
|
||||
|
||||
span.preprocessor {
|
||||
color: #806020
|
||||
}
|
||||
|
||||
span.stringliteral {
|
||||
color: #002080
|
||||
}
|
||||
|
||||
span.charliteral {
|
||||
color: #008080
|
||||
}
|
||||
|
||||
span.vhdldigit {
|
||||
color: #ff00ff
|
||||
}
|
||||
|
||||
span.vhdlchar {
|
||||
color: #000000
|
||||
}
|
||||
|
||||
span.vhdlkeyword {
|
||||
color: #700070
|
||||
}
|
||||
|
||||
span.vhdllogic {
|
||||
color: #ff0000
|
||||
}
|
||||
|
||||
blockquote {
|
||||
background-color: #F7F8FB;
|
||||
border-left: 2px solid #9CAFD4;
|
||||
margin: 0 24px 0 4px;
|
||||
padding: 0 12px 0 16px;
|
||||
}
|
||||
|
||||
/*---------------- Search Box */
|
||||
|
||||
#search-box {
|
||||
margin: 10px 0px;
|
||||
}
|
||||
#search-box .close {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
padding: 6px 12px;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
/*---------------- Search results window */
|
||||
|
||||
#search-results-window {
|
||||
display: none;
|
||||
}
|
||||
|
||||
iframe#MSearchResults {
|
||||
width: 100%;
|
||||
height: 15em;
|
||||
}
|
||||
|
||||
.SRChildren {
|
||||
padding-left: 3ex; padding-bottom: .5em
|
||||
}
|
||||
.SRPage .SRChildren {
|
||||
display: none;
|
||||
}
|
||||
a.SRScope {
|
||||
display: block;
|
||||
}
|
||||
a.SRSymbol:focus, a.SRSymbol:active,
|
||||
a.SRScope:focus, a.SRScope:active {
|
||||
text-decoration: underline;
|
||||
}
|
||||
span.SRScope {
|
||||
padding-left: 4px;
|
||||
}
|
||||
.SRResult {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* class and file list */
|
||||
.directory .icona,
|
||||
.directory .arrow {
|
||||
height: auto;
|
||||
}
|
||||
.directory .icona .icon {
|
||||
height: 16px;
|
||||
}
|
||||
.directory .icondoc {
|
||||
background-position: 0px 0px;
|
||||
height: 20px;
|
||||
}
|
||||
.directory .iconfopen {
|
||||
background-position: 0px 0px;
|
||||
}
|
||||
.directory td.entry {
|
||||
padding: 7px 8px 6px 8px;
|
||||
}
|
||||
|
||||
.table > tbody > tr > td.memSeparator {
|
||||
line-height: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.memItemLeft, .memTemplItemLeft {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
/* enumerations */
|
||||
.panel-body thead > tr {
|
||||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
/* todo lists */
|
||||
.todoname,
|
||||
.todoname a {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Class title */
|
||||
.summary {
|
||||
margin-top: 25px;
|
||||
}
|
||||
.page-header {
|
||||
margin: 20px 0px !important;
|
||||
}
|
||||
.page-header {
|
||||
#display: inline-block;
|
||||
}
|
||||
.title {
|
||||
text-align: center;
|
||||
color: orange;
|
||||
}
|
||||
.page-header .pull-right {
|
||||
margin-top: 0.3em;
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
.page-header .label {
|
||||
font-size: 50%;
|
||||
}
|
||||
|
||||
#main-nav {
|
||||
display: none;
|
||||
}
|
83
doc/build.md
Normal file
83
doc/build.md
Normal file
@ -0,0 +1,83 @@
|
||||
Build lib & build sample {#audio_orchestra_build}
|
||||
========================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
Download: {#audio_orchestra_build_download}
|
||||
=========
|
||||
|
||||
ege use some tools to manage source and build it:
|
||||
|
||||
need google repo: {#audio_orchestra_build_download_repo}
|
||||
-----------------
|
||||
|
||||
see: http://source.android.com/source/downloading.html#installing-repo
|
||||
|
||||
On all platform:
|
||||
```{.sh}
|
||||
mkdir ~/.bin
|
||||
PATH=~/.bin:$PATH
|
||||
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/.bin/repo
|
||||
chmod a+x ~/.bin/repo
|
||||
```
|
||||
|
||||
On ubuntu
|
||||
```{.sh}
|
||||
sudo apt-get install repo
|
||||
```
|
||||
|
||||
On archlinux
|
||||
```{.sh}
|
||||
sudo pacman -S repo
|
||||
```
|
||||
|
||||
lutin (build-system): {#audio_orchestra_build_download_lutin}
|
||||
---------------------
|
||||
|
||||
```{.sh}
|
||||
pip install lutin --user
|
||||
# optionnal dependency of lutin (manage image changing size for application release)
|
||||
pip install pillow --user
|
||||
```
|
||||
|
||||
|
||||
dependency: {#audio_orchestra_build_download_dependency}
|
||||
-----------
|
||||
|
||||
```{.sh}
|
||||
mkdir -p WORKING_DIRECTORY/framework
|
||||
cd WORKING_DIRECTORY/framework
|
||||
repo init -u git://github.com/atria-soft/manifest.git
|
||||
repo sync -j8
|
||||
cd ../..
|
||||
```
|
||||
|
||||
sources: {#audio_orchestra_build_download_sources}
|
||||
--------
|
||||
|
||||
They are already download in the repo manifest in:
|
||||
|
||||
```{.sh}
|
||||
cd WORKING_DIRECTORY/framework/atria-soft/audio_orchestra
|
||||
```
|
||||
|
||||
Build: {#audio_orchestra_build_build}
|
||||
======
|
||||
|
||||
you must stay in zour working directory...
|
||||
```{.sh}
|
||||
cd WORKING_DIRECTORY
|
||||
```
|
||||
|
||||
library: {#audio_orchestra_build_build_library}
|
||||
--------
|
||||
|
||||
```{.sh}
|
||||
lutin -mdebug audio-orchestra
|
||||
```
|
||||
|
||||
Sample: {#audio_orchestra_build_build_sample}
|
||||
-------
|
||||
|
||||
No smaple availlable for now ...
|
||||
|
50
doc/mainpage.md
Normal file
50
doc/mainpage.md
Normal file
@ -0,0 +1,50 @@
|
||||
AUDIO-ORCHESTRA library {#mainpage}
|
||||
=======================
|
||||
|
||||
@tableofcontents
|
||||
|
||||
What is AUDIO-ORCHESTRA: {#audio_orchestra_mainpage_what}
|
||||
========================
|
||||
|
||||
AUDIO-ORCHESTRA, is a fork of RTAudio lib (with port for Android, and IOs).
|
||||
|
||||
This is a cross API of Audio wrapping the Hardware.
|
||||
|
||||
This library is not friendy usable, use audio-river to have a correct and simple multiple-flow API
|
||||
|
||||
What it does: {#audio_orchestra_mainpage_what_it_does}
|
||||
-------------
|
||||
|
||||
- Open a strem audio in Input or output
|
||||
- synchronise 2 flow
|
||||
- open on some platform: Android, Linux, MacOs, Ios, Windows
|
||||
|
||||
AUDIO-ORCHESTRA is dependent of the STL (compatible with MacOs stl (CXX))
|
||||
|
||||
|
||||
What languages are supported? {#audio_orchestra_mainpage_language}
|
||||
=============================
|
||||
|
||||
AUDIO-ORCHESTRA is written in C++.
|
||||
|
||||
|
||||
Are there any licensing restrictions? {#audio_orchestra_mainpage_license_restriction}
|
||||
=====================================
|
||||
|
||||
AUDIO-ORCHESTRA is **FREE software** and _all sub-library are FREE and staticly linkable !!!_
|
||||
|
||||
|
||||
License (MIT) {#audio_orchestra_mainpage_license}
|
||||
=============
|
||||
|
||||
Copyright AUDIO-ORCHESTRA Edouard DUPIN
|
||||
|
||||
MIT ...
|
||||
|
||||
|
||||
Other pages {#audio_orchestra_mainpage_sub_page}
|
||||
===========
|
||||
|
||||
- @ref audio_orchestra_build
|
||||
- [**ewol coding style**](http://atria-soft.github.io/ewol/ewol_coding_style.html)
|
||||
|
264
doxy-boot.js
264
doxy-boot.js
@ -1,264 +0,0 @@
|
||||
$( document ).ready(function() {
|
||||
|
||||
$("div.headertitle").addClass("page-header");
|
||||
$("div.title").addClass("h1");
|
||||
|
||||
$('li > a[href="index.html"] > span').before("<i class='fa fa-cog'></i> ");
|
||||
$('li > a[href="modules.html"] > span').before("<i class='fa fa-square'></i> ");
|
||||
$('li > a[href="namespaces.html"] > span').before("<i class='fa fa-bars'></i> ");
|
||||
$('li > a[href="annotated.html"] > span').before("<i class='fa fa-list-ul'></i> ");
|
||||
$('li > a[href="classes.html"] > span').before("<i class='fa fa-book'></i> ");
|
||||
$('li > a[href="inherits.html"] > span').before("<i class='fa fa-sitemap'></i> ");
|
||||
$('li > a[href="functions.html"] > span').before("<i class='fa fa-list'></i> ");
|
||||
$('li > a[href="functions_func.html"] > span').before("<i class='fa fa-list'></i> ");
|
||||
$('li > a[href="functions_vars.html"] > span').before("<i class='fa fa-list'></i> ");
|
||||
$('li > a[href="functions_enum.html"] > span').before("<i class='fa fa-list'></i> ");
|
||||
$('li > a[href="functions_eval.html"] > span').before("<i class='fa fa-list'></i> ");
|
||||
$('img[src="ftv2ns.png"]').replaceWith('<span class="label label-danger">N</span> ');
|
||||
$('img[src="ftv2cl.png"]').replaceWith('<span class="label label-danger">C</span> ');
|
||||
|
||||
$("ul.tablist").addClass("nav nav-pills nav-justified");
|
||||
$("ul.tablist").css("margin-top", "0.5em");
|
||||
$("ul.tablist").css("margin-bottom", "0.5em");
|
||||
$("li.current").addClass("active");
|
||||
$("iframe").attr("scrolling", "yes");
|
||||
|
||||
$("#nav-path > ul").addClass("breadcrumb");
|
||||
|
||||
$("table.params").addClass("table");
|
||||
$("div.ingroups").wrapInner("<small></small>");
|
||||
$("div.levels").css("margin", "0.5em");
|
||||
$("div.levels > span").addClass("btn btn-default btn-xs");
|
||||
$("div.levels > span").css("margin-right", "0.25em");
|
||||
|
||||
$("table.directory").addClass("table table-striped");
|
||||
$("div.summary > a").addClass("btn btn-default btn-xs");
|
||||
$("table.fieldtable").addClass("table");
|
||||
$(".fragment").addClass("well");
|
||||
$(".memitem").addClass("panel panel-default");
|
||||
$(".memproto").addClass("panel-heading");
|
||||
$(".memdoc").addClass("panel-body");
|
||||
$("span.mlabel").addClass("label label-info");
|
||||
|
||||
$("table.memberdecls").addClass("table");
|
||||
$("[class^=memitem]").addClass("active");
|
||||
|
||||
$("div.ah").addClass("btn btn-default");
|
||||
$("span.mlabels").addClass("pull-right");
|
||||
$("table.mlabels").css("width", "100%")
|
||||
$("td.mlabels-right").addClass("pull-right");
|
||||
|
||||
$("div.ttc").addClass("panel panel-primary");
|
||||
$("div.ttname").addClass("panel-heading");
|
||||
$("div.ttname a").css("color", 'white');
|
||||
$("div.ttdef,div.ttdoc,div.ttdeci").addClass("panel-body");
|
||||
|
||||
$('div.fragment.well div.line:first').css('margin-top', '15px');
|
||||
$('div.fragment.well div.line:last').css('margin-bottom', '15px');
|
||||
|
||||
$('table.doxtable').removeClass('doxtable').addClass('table table-striped table-bordered').each(function(){
|
||||
$(this).prepend('<thead></thead>');
|
||||
$(this).find('tbody > tr:first').prependTo($(this).find('thead'));
|
||||
|
||||
$(this).find('td > span.success').parent().addClass('success');
|
||||
$(this).find('td > span.warning').parent().addClass('warning');
|
||||
$(this).find('td > span.danger').parent().addClass('danger');
|
||||
});
|
||||
|
||||
|
||||
|
||||
if($('div.fragment.well div.ttc').length > 0)
|
||||
{
|
||||
$('div.fragment.well div.line:first').parent().removeClass('fragment well');
|
||||
}
|
||||
//merge left ad right element in the fuction table item
|
||||
/*
|
||||
$('table.memberdecls').find('.memItemRight').each(function(){
|
||||
$(this).contents().appendTo($(this).siblings('.memItemLeft'));
|
||||
$(this).siblings('.memItemLeft').attr('align', 'left');
|
||||
});
|
||||
*/
|
||||
|
||||
function getOriginalWidthOfImg(img_element) {
|
||||
var t = new Image();
|
||||
t.src = (img_element.getAttribute ? img_element.getAttribute("src") : false) || img_element.src;
|
||||
return t.width;
|
||||
}
|
||||
|
||||
$('div.dyncontent').find('img').each(function(){
|
||||
if(getOriginalWidthOfImg($(this)[0]) > $('#content>div.container').width())
|
||||
$(this).css('width', '100%');
|
||||
});
|
||||
|
||||
|
||||
/* responsive search box */
|
||||
|
||||
$('#MSearchBox').parent().remove();
|
||||
|
||||
var nav_container = $('<div class="row"></div>');
|
||||
$('#navrow1').parent().prepend(nav_container);
|
||||
|
||||
var left_nav = $('<div class="col-md-9"></div>');
|
||||
for (i = 0; i < 6; i++) {
|
||||
var navrow = $('#navrow' + i + ' > ul.tablist').detach();
|
||||
left_nav.append(navrow);
|
||||
$('#navrow' + i).remove();
|
||||
}
|
||||
var right_nav = $('<div class="col-md-3"></div>').append('\
|
||||
<div id="search-box" class="input-group">\
|
||||
<div class="input-group-btn">\
|
||||
<button aria-expanded="false" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">\
|
||||
<span class="glyphicon glyphicon-search"></span> <span class="caret"></span>\
|
||||
</button>\
|
||||
<ul class="dropdown-menu">\
|
||||
</ul>\
|
||||
</div>\
|
||||
<button id="search-close" type="button" class="close" aria-label="Close"><span aria-hidden="true">×</span></button>\
|
||||
<input id="search-field" class="form-control" accesskey="S" onkeydown="searchBox.OnSearchFieldChange(event);" placeholder="Search ..." type="text">\
|
||||
</div>');
|
||||
$(nav_container).append(left_nav);
|
||||
$(nav_container).append(right_nav);
|
||||
|
||||
$('#MSearchSelectWindow .SelectionMark').remove();
|
||||
var search_selectors = $('#MSearchSelectWindow .SelectItem');
|
||||
for (var i = 0; i < search_selectors.length; i += 1) {
|
||||
var element_a = $('<a href="#"></a>').text($(search_selectors[i]).text());
|
||||
|
||||
element_a.click(function(){
|
||||
$('#search-box .dropdown-menu li').removeClass('active');
|
||||
$(this).parent().addClass('active');
|
||||
searchBox.OnSelectItem($('#search-box li a').index(this));
|
||||
searchBox.Search();
|
||||
return false;
|
||||
});
|
||||
|
||||
var element = $('<li></li>').append(element_a);
|
||||
$('#search-box .dropdown-menu').append(element);
|
||||
}
|
||||
$('#MSearchSelectWindow').remove();
|
||||
|
||||
$('#search-box .close').click(function (){
|
||||
searchBox.CloseResultsWindow();
|
||||
});
|
||||
|
||||
$('body').append('<div id="MSearchClose"></div>');
|
||||
$('body').append('<div id="MSearchBox"></div>');
|
||||
$('body').append('<div id="MSearchSelectWindow"></div>');
|
||||
|
||||
searchBox.searchLabel = '';
|
||||
searchBox.DOMSearchField = function() {
|
||||
return document.getElementById("search-field");
|
||||
}
|
||||
searchBox.DOMSearchClose = function(){
|
||||
return document.getElementById("search-close");
|
||||
}
|
||||
|
||||
|
||||
/* search results */
|
||||
var results_iframe = $('#MSearchResults').detach();
|
||||
$('#MSearchResultsWindow')
|
||||
.attr('id', 'search-results-window')
|
||||
.addClass('panel panel-default')
|
||||
.append(
|
||||
'<div class="panel-heading">\
|
||||
<h3 class="panel-title">Search Results</h3>\
|
||||
</div>\
|
||||
<div class="panel-body"></div>'
|
||||
);
|
||||
$('#search-results-window .panel-body').append(results_iframe);
|
||||
|
||||
searchBox.DOMPopupSearchResultsWindow = function() {
|
||||
return document.getElementById("search-results-window");
|
||||
}
|
||||
|
||||
function update_search_results_window() {
|
||||
$('#search-results-window').removeClass('panel-default panel-success panel-warning panel-danger')
|
||||
var status = $('#MSearchResults').contents().find('.SRStatus:visible');
|
||||
if (status.length > 0) {
|
||||
switch(status.attr('id')) {
|
||||
case 'Loading':
|
||||
case 'Searching':
|
||||
$('#search-results-window').addClass('panel-warning');
|
||||
break;
|
||||
case 'NoMatches':
|
||||
$('#search-results-window').addClass('panel-danger');
|
||||
break;
|
||||
default:
|
||||
$('#search-results-window').addClass('panel-default');
|
||||
}
|
||||
} else {
|
||||
$('#search-results-window').addClass('panel-success');
|
||||
}
|
||||
}
|
||||
$('#MSearchResults').load(function() {
|
||||
$('#MSearchResults').contents().find('link[href="search.css"]').attr('href','../doxygen.css');
|
||||
$('#MSearchResults').contents().find('head').append(
|
||||
'<link href="../customdoxygen.css" rel="stylesheet" type="text/css">');
|
||||
|
||||
update_search_results_window();
|
||||
|
||||
// detect status changes (only for search with external search backend)
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
update_search_results_window();
|
||||
});
|
||||
var config = {
|
||||
attributes: true
|
||||
};
|
||||
|
||||
var targets = $('#MSearchResults').contents().find('.SRStatus');
|
||||
for (i = 0; i < targets.length; i++) {
|
||||
observer.observe(targets[i], config);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/* enumerations */
|
||||
$('table.fieldtable').removeClass('fieldtable').addClass('table table-striped table-bordered').each(function(){
|
||||
$(this).prepend('<thead></thead>');
|
||||
$(this).find('tbody > tr:first').prependTo($(this).find('thead'));
|
||||
|
||||
$(this).find('td > span.success').parent().addClass('success');
|
||||
$(this).find('td > span.warning').parent().addClass('warning');
|
||||
$(this).find('td > span.danger').parent().addClass('danger');
|
||||
});
|
||||
|
||||
/* todo list */
|
||||
var todoelements = $('.contents > .textblock > dl.reflist > dt, .contents > .textblock > dl.reflist > dd');
|
||||
for (var i = 0; i < todoelements.length; i += 2) {
|
||||
$('.contents > .textblock').append(
|
||||
'<div class="panel panel-default active">'
|
||||
+ "<div class=\"panel-heading todoname\">" + $(todoelements[i]).html() + "</div>"
|
||||
+ "<div class=\"panel-body\">" + $(todoelements[i+1]).html() + "</div>"
|
||||
+ '</div>');
|
||||
}
|
||||
$('.contents > .textblock > dl').remove();
|
||||
|
||||
|
||||
$(".memitem").removeClass('memitem');
|
||||
$(".memproto").removeClass('memproto');
|
||||
$(".memdoc").removeClass('memdoc');
|
||||
$("span.mlabel").removeClass('mlabel');
|
||||
$("table.memberdecls").removeClass('memberdecls');
|
||||
$("[class^=memitem]").removeClass('memitem');
|
||||
$("span.mlabels").removeClass('mlabels');
|
||||
$("table.mlabels").removeClass('mlabels');
|
||||
$("td.mlabels-right").removeClass('mlabels-right');
|
||||
$(".navpath").removeClass('navpath');
|
||||
$("li.navelem").removeClass('navelem');
|
||||
$("a.el").removeClass('el');
|
||||
$("div.ah").removeClass('ah');
|
||||
$("div.header").removeClass("header");
|
||||
|
||||
$('.mdescLeft').each(function(){
|
||||
if($(this).html()==" ") {
|
||||
$(this).siblings('.mdescRight').attr('colspan', 2);
|
||||
$(this).remove();
|
||||
}
|
||||
});
|
||||
$('td.memItemLeft').each(function(){
|
||||
if($(this).siblings('.memItemRight').html()=="") {
|
||||
$(this).attr('colspan', 2);
|
||||
$(this).siblings('.memItemRight').remove();
|
||||
}
|
||||
});
|
||||
});
|
32
doxy_audio-orchestra.py
Normal file
32
doxy_audio-orchestra.py
Normal file
@ -0,0 +1,32 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import doxy.module as module
|
||||
import doxy.debug as debug
|
||||
import doxy.tools as tools
|
||||
|
||||
def create(target, module_name):
|
||||
my_module = module.Module(__file__, module_name)
|
||||
my_module.set_version("version.txt")
|
||||
my_module.set_title("Orchestra: audio interface wrapper")
|
||||
my_module.set_website("http://musicdsp.github.io/" + module_name)
|
||||
my_module.set_website_sources("http://github.com/musicdsp/" + module_name)
|
||||
my_module.add_path([
|
||||
"audio",
|
||||
"doc"
|
||||
])
|
||||
my_module.add_depend([
|
||||
'etk',
|
||||
'audio',
|
||||
])
|
||||
my_module.add_exclude_symbols([
|
||||
'*operator<<*',
|
||||
])
|
||||
my_module.add_exclude_file([
|
||||
'debug.h',
|
||||
])
|
||||
my_module.add_file_patterns([
|
||||
'*.h',
|
||||
'*.md',
|
||||
])
|
||||
|
||||
return my_module
|
1508
doxygen.css
1508
doxygen.css
File diff suppressed because it is too large
Load Diff
BIN
doxygen.png
BIN
doxygen.png
Binary file not shown.
Before Width: | Height: | Size: 3.7 KiB |
@ -1,97 +0,0 @@
|
||||
function toggleVisibility(linkObj)
|
||||
{
|
||||
var base = $(linkObj).attr('id');
|
||||
var summary = $('#'+base+'-summary');
|
||||
var content = $('#'+base+'-content');
|
||||
var trigger = $('#'+base+'-trigger');
|
||||
var src=$(trigger).attr('src');
|
||||
if (content.is(':visible')===true) {
|
||||
content.hide();
|
||||
summary.show();
|
||||
$(linkObj).addClass('closed').removeClass('opened');
|
||||
$(trigger).attr('src',src.substring(0,src.length-8)+'closed.png');
|
||||
} else {
|
||||
content.show();
|
||||
summary.hide();
|
||||
$(linkObj).removeClass('closed').addClass('opened');
|
||||
$(trigger).attr('src',src.substring(0,src.length-10)+'open.png');
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function updateStripes()
|
||||
{
|
||||
$('table.directory tr').
|
||||
removeClass('even').filter(':visible:even').addClass('even');
|
||||
}
|
||||
|
||||
function toggleLevel(level)
|
||||
{
|
||||
$('table.directory tr').each(function() {
|
||||
var l = this.id.split('_').length-1;
|
||||
var i = $('#img'+this.id.substring(3));
|
||||
var a = $('#arr'+this.id.substring(3));
|
||||
if (l<level+1) {
|
||||
i.removeClass('iconfopen iconfclosed').addClass('iconfopen');
|
||||
a.html('▼');
|
||||
$(this).show();
|
||||
} else if (l==level+1) {
|
||||
i.removeClass('iconfclosed iconfopen').addClass('iconfclosed');
|
||||
a.html('►');
|
||||
$(this).show();
|
||||
} else {
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
updateStripes();
|
||||
}
|
||||
|
||||
function toggleFolder(id)
|
||||
{
|
||||
// the clicked row
|
||||
var currentRow = $('#row_'+id);
|
||||
|
||||
// all rows after the clicked row
|
||||
var rows = currentRow.nextAll("tr");
|
||||
|
||||
var re = new RegExp('^row_'+id+'\\d+_$', "i"); //only one sub
|
||||
|
||||
// only match elements AFTER this one (can't hide elements before)
|
||||
var childRows = rows.filter(function() { return this.id.match(re); });
|
||||
|
||||
// first row is visible we are HIDING
|
||||
if (childRows.filter(':first').is(':visible')===true) {
|
||||
// replace down arrow by right arrow for current row
|
||||
var currentRowSpans = currentRow.find("span");
|
||||
currentRowSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");
|
||||
currentRowSpans.filter(".arrow").html('►');
|
||||
rows.filter("[id^=row_"+id+"]").hide(); // hide all children
|
||||
} else { // we are SHOWING
|
||||
// replace right arrow by down arrow for current row
|
||||
var currentRowSpans = currentRow.find("span");
|
||||
currentRowSpans.filter(".iconfclosed").removeClass("iconfclosed").addClass("iconfopen");
|
||||
currentRowSpans.filter(".arrow").html('▼');
|
||||
// replace down arrows by right arrows for child rows
|
||||
var childRowsSpans = childRows.find("span");
|
||||
childRowsSpans.filter(".iconfopen").removeClass("iconfopen").addClass("iconfclosed");
|
||||
childRowsSpans.filter(".arrow").html('►');
|
||||
childRows.show(); //show all children
|
||||
}
|
||||
updateStripes();
|
||||
}
|
||||
|
||||
|
||||
function toggleInherit(id)
|
||||
{
|
||||
var rows = $('tr.inherit.'+id);
|
||||
var img = $('tr.inherit_header.'+id+' img');
|
||||
var src = $(img).attr('src');
|
||||
if (rows.filter(':first').is(':visible')===true) {
|
||||
rows.css('display','none');
|
||||
$(img).attr('src',src.substring(0,src.length-8)+'closed.png');
|
||||
} else {
|
||||
rows.css('display','table-row'); // using show() causes jump in firefox
|
||||
$(img).attr('src',src.substring(0,src.length-10)+'open.png');
|
||||
}
|
||||
}
|
||||
|
BIN
folderclosed.png
BIN
folderclosed.png
Binary file not shown.
Before Width: | Height: | Size: 616 B |
BIN
folderopen.png
BIN
folderopen.png
Binary file not shown.
Before Width: | Height: | Size: 597 B |
190
index.html
190
index.html
@ -1,190 +0,0 @@
|
||||
<!-- HTML header for doxygen 1.8.8-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- For Mobile Devices -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
|
||||
<title>Orchestra: audio interface wrapper: AUDIO-ORCHESTRA library</title>
|
||||
<!--<link href="tabs.css" rel="stylesheet" type="text/css"/>-->
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="search/searchdata.js"></script>
|
||||
<script type="text/javascript" src="search/search.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="customdoxygen.css" rel="stylesheet" type="text/css"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="doxy-boot.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand">Orchestra: audio interface wrapper 0.4.0</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="index.html">Main Page</a></li>
|
||||
<li><a href="pages.html">Related Pages</a></li>
|
||||
<li><a href="namespaces.html">Namespaces</a></li>
|
||||
<li><a href="annotated.html">Classes</a></li>
|
||||
<li><a href="files.html">Files</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
Link-libs<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://HeeroYui.github.io/lutin">lutin</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ewol">ewol</a></li>
|
||||
<li><a href="http://atria-soft.github.io/echrono">echrono</a></li>
|
||||
<li><a href="http://atria-soft.github.io/etk">etk</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ejson">ejson</a></li>
|
||||
<li><a href="http://atria-soft.github.io/exml">exml</a></li>
|
||||
<li><a href="http://atria-soft.github.io/esvg">esvg</a></li>
|
||||
<li><a href="http://atria-soft.github.io/egami">egami</a></li>
|
||||
<li><a href="http://atria-soft.github.io/gale">gale</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ege">ege</a></li>
|
||||
<li><a href="http://atria-soft.github.io/elog">elog</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ememory">ememory</a></li>
|
||||
<li><a href="http://atria-soft.github.io/enet">enet</a></li>
|
||||
<li><a href="http://atria-soft.github.io/eproperty">eproperty</a></li>
|
||||
<li><a href="http://atria-soft.github.io/esignal">esignal</a></li>
|
||||
<li><a href="http://atria-soft.github.io/etranslate">etranslate</a></li>
|
||||
<li><a href="http://atria-soft.github.io/zeus">zeus</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-ess">audio-ess</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio">audio</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-drain">audio-drain</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-orchestra">audio-orchestra</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-river">audio-river</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="search-box" class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button aria-expanded="false" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-search"></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#">All</a></li>
|
||||
<li><a href="#">Classes</a></li>
|
||||
<li><a href="#">Namespaces</a></li>
|
||||
<li><a href="#">Files</a></li>
|
||||
<li><a href="#">Functions</a></li>
|
||||
<li><a href="#">Variables</a></li>
|
||||
<li><a href="#">Typedefs</a></li>
|
||||
<li><a href="#">Enumerations</a></li>
|
||||
<li><a href="#">Enumerator</a></li>
|
||||
<li><a href="#">Friends</a></li>
|
||||
<li><a href="#">Macros</a></li>
|
||||
<li><a href="#">Pages</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button id="search-close" type="button" class="close" aria-label="Close">
|
||||
<span aria-hidden="true"></span>
|
||||
</button>
|
||||
<input id="search-field" class="form-control" accesskey="S" onkeydown="searchBox.OnSearchFieldChange(event);" placeholder="Search ..." type="text">
|
||||
</div>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</nav>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div class="content" id="content">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 panel panel-default" style="padding-bottom: 15px;">
|
||||
<div style="margin-bottom: 15px;margin-top: 60px;">
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.12 -->
|
||||
<script type="text/javascript">
|
||||
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||||
</script>
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',true,false,'search.php','Search');
|
||||
$(document).ready(function() { init_search(); });
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
</div><!-- top -->
|
||||
<!-- window showing the filter options -->
|
||||
<div id="MSearchSelectWindow"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||||
</div>
|
||||
|
||||
<!-- iframe showing the search results (closed by default) -->
|
||||
<div id="MSearchResultsWindow">
|
||||
<iframe src="javascript:void(0)" frameborder="0"
|
||||
name="MSearchResults" id="MSearchResults">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">AUDIO-ORCHESTRA library </div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="toc"><h3>Table of Contents</h3>
|
||||
<ul><li class="level1"><a href="#audio_orchestra_mainpage_what">What is AUDIO-ORCHESTRA: </a><ul><li class="level2"><a href="#audio_orchestra_mainpage_what_it_does">What it does: </a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="level1"><a href="#audio_orchestra_mainpage_language">What languages are supported? </a></li>
|
||||
<li class="level1"><a href="#audio_orchestra_mainpage_license_restriction">Are there any licensing restrictions? </a></li>
|
||||
<li class="level1"><a href="#audio_orchestra_mainpage_license">License (MIT) </a></li>
|
||||
<li class="level1"><a href="#audio_orchestra_mainpage_sub_page">Other pages </a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="textblock"><h1><a class="anchor" id="audio_orchestra_mainpage_what"></a>
|
||||
What is AUDIO-ORCHESTRA: </h1>
|
||||
<p>AUDIO-ORCHESTRA, is a fork of RTAudio lib (with port for Android, and IOs).</p>
|
||||
<p>This is a cross API of Audio wrapping the Hardware.</p>
|
||||
<p>This library is not friendy usable, use audio-river to have a correct and simple multiple-flow API</p>
|
||||
<h2><a class="anchor" id="audio_orchestra_mainpage_what_it_does"></a>
|
||||
What it does: </h2>
|
||||
<ul>
|
||||
<li>Open a strem audio in Input or output</li>
|
||||
<li>synchronise 2 flow</li>
|
||||
<li>open on some platform: Android, Linux, MacOs, Ios, Windows</li>
|
||||
</ul>
|
||||
<p>AUDIO-ORCHESTRA is dependent of the STL (compatible with MacOs stl (CXX))</p>
|
||||
<h1><a class="anchor" id="audio_orchestra_mainpage_language"></a>
|
||||
What languages are supported? </h1>
|
||||
<p>AUDIO-ORCHESTRA is written in C++.</p>
|
||||
<h1><a class="anchor" id="audio_orchestra_mainpage_license_restriction"></a>
|
||||
Are there any licensing restrictions? </h1>
|
||||
<p>AUDIO-ORCHESTRA is <b>FREE software</b> and <em>all sub-library are FREE and staticly linkable !!!</em></p>
|
||||
<h1><a class="anchor" id="audio_orchestra_mainpage_license"></a>
|
||||
License (MIT) </h1>
|
||||
<p>Copyright AUDIO-ORCHESTRA Edouard DUPIN</p>
|
||||
<p>MIT ...</p>
|
||||
<h1><a class="anchor" id="audio_orchestra_mainpage_sub_page"></a>
|
||||
Other pages </h1>
|
||||
<ul>
|
||||
<li><a class="el" href="audio_orchestra_build.html">Build lib & build sample</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ewol/ewol_coding_style.html"><b>ewol coding style</b></a> </li>
|
||||
</ul>
|
||||
</div></div><!-- contents -->
|
||||
<!-- HTML footer for doxygen 1.8.8-->
|
||||
<!-- start footer part -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated on Mon Oct 24 2016 15:35:48 for Orchestra: audio interface wrapper by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.12
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
182
lutin_audio-orchestra.py
Normal file
182
lutin_audio-orchestra.py
Normal file
@ -0,0 +1,182 @@
|
||||
#!/usr/bin/python
|
||||
import lutin.tools as tools
|
||||
import realog.debug as debug
|
||||
|
||||
|
||||
def get_type():
|
||||
return "LIBRARY"
|
||||
|
||||
def get_desc():
|
||||
return "Generic wrapper on all audio interface"
|
||||
|
||||
def get_licence():
|
||||
return "APACHE-2"
|
||||
|
||||
def get_compagny_type():
|
||||
return "com"
|
||||
|
||||
def get_compagny_name():
|
||||
return "atria-soft"
|
||||
|
||||
def get_maintainer():
|
||||
return "authors.txt"
|
||||
|
||||
def get_version():
|
||||
return "version.txt"
|
||||
|
||||
def configure(target, my_module):
|
||||
my_module.add_src_file([
|
||||
'audio/orchestra/debug.cpp',
|
||||
'audio/orchestra/status.cpp',
|
||||
'audio/orchestra/type.cpp',
|
||||
'audio/orchestra/mode.cpp',
|
||||
'audio/orchestra/state.cpp',
|
||||
'audio/orchestra/error.cpp',
|
||||
'audio/orchestra/base.cpp',
|
||||
'audio/orchestra/Interface.cpp',
|
||||
'audio/orchestra/Flags.cpp',
|
||||
'audio/orchestra/Api.cpp',
|
||||
'audio/orchestra/DeviceInfo.cpp',
|
||||
'audio/orchestra/StreamOptions.cpp',
|
||||
'audio/orchestra/api/Dummy.cpp'
|
||||
])
|
||||
my_module.add_header_file([
|
||||
'audio/orchestra/debug.hpp',
|
||||
'audio/orchestra/status.hpp',
|
||||
'audio/orchestra/type.hpp',
|
||||
'audio/orchestra/mode.hpp',
|
||||
'audio/orchestra/state.hpp',
|
||||
'audio/orchestra/error.hpp',
|
||||
'audio/orchestra/base.hpp',
|
||||
'audio/orchestra/Interface.hpp',
|
||||
'audio/orchestra/Flags.hpp',
|
||||
'audio/orchestra/Api.hpp',
|
||||
'audio/orchestra/DeviceInfo.hpp',
|
||||
'audio/orchestra/StreamOptions.hpp',
|
||||
'audio/orchestra/CallbackInfo.hpp',
|
||||
'audio/orchestra/StreamParameters.hpp'
|
||||
])
|
||||
my_module.add_depend([
|
||||
'audio',
|
||||
'etk'
|
||||
])
|
||||
# add all the time the dummy interface
|
||||
my_module.add_flag('c++', ['-DORCHESTRA_BUILD_DUMMY'], export=True)
|
||||
# TODO : Add a FILE interface:
|
||||
|
||||
if "Windows" in target.get_type():
|
||||
my_module.add_src_file([
|
||||
'audio/orchestra/api/Asio.cpp',
|
||||
'audio/orchestra/api/Ds.cpp',
|
||||
])
|
||||
# load optionnal API:
|
||||
my_module.add_optionnal_depend('asio', ["c++", "-DORCHESTRA_BUILD_ASIO"])
|
||||
my_module.add_optionnal_depend('ds', ["c++", "-DORCHESTRA_BUILD_DS"])
|
||||
my_module.add_optionnal_depend('wasapi', ["c++", "-DORCHESTRA_BUILD_WASAPI"])
|
||||
elif "Linux" in target.get_type():
|
||||
my_module.add_src_file([
|
||||
'audio/orchestra/api/Alsa.cpp',
|
||||
'audio/orchestra/api/Jack.cpp',
|
||||
'audio/orchestra/api/Pulse.cpp',
|
||||
'audio/orchestra/api/PulseDeviceList.cpp'
|
||||
])
|
||||
my_module.add_optionnal_depend('alsa', ["c++", "-DORCHESTRA_BUILD_ALSA"])
|
||||
my_module.add_optionnal_depend('jack', ["c++", "-DORCHESTRA_BUILD_JACK"])
|
||||
my_module.add_optionnal_depend('pulse', ["c++", "-DORCHESTRA_BUILD_PULSE"])
|
||||
elif "MacOs" in target.get_type():
|
||||
my_module.add_src_file([
|
||||
'audio/orchestra/api/Core.cpp'
|
||||
])
|
||||
# MacOsX core
|
||||
my_module.add_optionnal_depend('CoreAudio', ["c++", "-DORCHESTRA_BUILD_MACOSX_CORE"])
|
||||
elif "IOs" in target.get_type():
|
||||
my_module.add_src_file('audio/orchestra/api/CoreIos.mm')
|
||||
# IOsX core
|
||||
my_module.add_optionnal_depend('CoreAudio', ["c++", "-DORCHESTRA_BUILD_IOS_CORE"])
|
||||
elif "Android" in target.get_type():
|
||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraConstants.java')
|
||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraManagerCallback.java')
|
||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraNative.java')
|
||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraInterfaceInput.java')
|
||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraInterfaceOutput.java')
|
||||
my_module.add_src_file('android/org/musicdsp/orchestra/OrchestraManager.java')
|
||||
# create inter language interfacef
|
||||
my_module.add_src_file('org.musicdsp.orchestra.OrchestraConstants.javah')
|
||||
my_module.add_path('android', type='java')
|
||||
my_module.add_depend(['SDK', 'jvm-basics', 'ejson'])
|
||||
my_module.add_flag('c++', ['-DORCHESTRA_BUILD_JAVA'], export=True)
|
||||
|
||||
my_module.add_src_file('audio/orchestra/api/Android.cpp')
|
||||
my_module.add_src_file('audio/orchestra/api/AndroidNativeInterface.cpp')
|
||||
# add tre creator of the basic java class ...
|
||||
target.add_action("BINARY", 11, "audio-orchestra-out-wrapper", tool_generate_add_java_section_in_class)
|
||||
else:
|
||||
debug.warning("unknow target for audio_orchestra : " + target.name);
|
||||
|
||||
my_module.add_path(".")
|
||||
|
||||
return True
|
||||
|
||||
|
||||
|
||||
##################################################################
|
||||
##
|
||||
## Android specific section
|
||||
##
|
||||
##################################################################
|
||||
def tool_generate_add_java_section_in_class(target, module, package_name):
|
||||
module.add_pkg("GENERATE_SECTION__IMPORT", [
|
||||
"import org.musicdsp.orchestra.OrchestraManager;"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__DECLARE", [
|
||||
"private OrchestraManager m_audioManagerHandle;"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__CONSTRUCTOR", [
|
||||
"// load audio maneger if it does not work, it is not critical ...",
|
||||
"try {",
|
||||
" m_audioManagerHandle = new OrchestraManager();",
|
||||
"} catch (RuntimeException e) {",
|
||||
" Log.e(\"" + package_name + "\", \"Can not load Audio interface (maybe not really needed) :\" + e);",
|
||||
"}"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__ON_CREATE", [
|
||||
"if (m_audioManagerHandle != null) {",
|
||||
" m_audioManagerHandle.onCreate();",
|
||||
"}"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__ON_START", [
|
||||
"if (m_audioManagerHandle != null) {",
|
||||
" m_audioManagerHandle.onStart();",
|
||||
"}"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__ON_RESTART", [
|
||||
"if (m_audioManagerHandle != null) {",
|
||||
" m_audioManagerHandle.onRestart();",
|
||||
"}"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__ON_RESUME", [
|
||||
"if (m_audioManagerHandle != null) {",
|
||||
" m_audioManagerHandle.onResume();",
|
||||
"}"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__ON_PAUSE", [
|
||||
"if (m_audioManagerHandle != null) {",
|
||||
" m_audioManagerHandle.onPause();",
|
||||
"}"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__ON_STOP", [
|
||||
"if (m_audioManagerHandle != null) {",
|
||||
" m_audioManagerHandle.onStop();",
|
||||
"}"
|
||||
])
|
||||
module.add_pkg("GENERATE_SECTION__ON_DESTROY", [
|
||||
"// Destroy the AdView.",
|
||||
"if (m_audioManagerHandle != null) {",
|
||||
" m_audioManagerHandle.onDestroy();",
|
||||
"}"
|
||||
])
|
||||
|
||||
|
||||
|
||||
|
||||
|
26
menu.js
26
menu.js
@ -1,26 +0,0 @@
|
||||
function initMenu(relPath,searchEnabled,serverSide,searchPage,search) {
|
||||
function makeTree(data,relPath) {
|
||||
var result='';
|
||||
if ('children' in data) {
|
||||
result+='<ul>';
|
||||
for (var i in data.children) {
|
||||
result+='<li><a href="'+relPath+data.children[i].url+'">'+
|
||||
data.children[i].text+'</a>'+
|
||||
makeTree(data.children[i],relPath)+'</li>';
|
||||
}
|
||||
result+='</ul>';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
$('#main-nav').append(makeTree(menudata,relPath));
|
||||
$('#main-nav').children(':first').addClass('sm sm-dox').attr('id','main-menu');
|
||||
if (searchEnabled) {
|
||||
if (serverSide) {
|
||||
$('#main-menu').append('<li style="float:right"><div id="MSearchBox" class="MSearchBoxInactive"><div class="left"><form id="FSearchBox" action="'+searchPage+'" method="get"><img id="MSearchSelect" src="'+relPath+'search/mag.png" alt=""/><input type="text" id="MSearchField" name="query" value="'+search+'" size="20" accesskey="S" onfocus="searchBox.OnSearchFieldFocus(true)" onblur="searchBox.OnSearchFieldFocus(false)"></form></div><div class="right"></div></div></li>');
|
||||
} else {
|
||||
$('#main-menu').append('<li style="float:right"><div id="MSearchBox" class="MSearchBoxInactive"><span class="left"><img id="MSearchSelect" src="'+relPath+'search/mag_sel.png" onmouseover="return searchBox.OnSearchSelectShow()" onmouseout="return searchBox.OnSearchSelectHide()" alt=""/><input type="text" id="MSearchField" value="'+search+'" accesskey="S" onfocus="searchBox.OnSearchFieldFocus(true)" onblur="searchBox.OnSearchFieldFocus(false)" onkeyup="searchBox.OnSearchFieldChange(event)"/></span><span class="right"><a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="'+relPath+'search/close.png" alt=""/></a></span></div></li>');
|
||||
}
|
||||
}
|
||||
$('#main-menu').smartmenus();
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
var menudata={children:[
|
||||
{text:'Main Page',url:'index.html'},
|
||||
{text:'Related Pages',url:'pages.html'}]}
|
156
pages.html
156
pages.html
@ -1,156 +0,0 @@
|
||||
<!-- HTML header for doxygen 1.8.8-->
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<!-- For Mobile Devices -->
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
|
||||
<title>Orchestra: audio interface wrapper: Related Pages</title>
|
||||
<!--<link href="tabs.css" rel="stylesheet" type="text/css"/>-->
|
||||
<script type="text/javascript" src="dynsections.js"></script>
|
||||
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
||||
<script type="text/javascript" src="search/searchdata.js"></script>
|
||||
<script type="text/javascript" src="search/search.js"></script>
|
||||
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
||||
<link href="customdoxygen.css" rel="stylesheet" type="text/css"/>
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css">
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js"></script>
|
||||
<script type="text/javascript" src="doxy-boot.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<nav class="navbar navbar-default navbar-fixed-top" role="navigation">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<a class="navbar-brand">Orchestra: audio interface wrapper 0.4.0</a>
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li><a href="index.html">Main Page</a></li>
|
||||
<li><a href="pages.html">Related Pages</a></li>
|
||||
<li><a href="namespaces.html">Namespaces</a></li>
|
||||
<li><a href="annotated.html">Classes</a></li>
|
||||
<li><a href="files.html">Files</a></li>
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">
|
||||
Link-libs<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="http://HeeroYui.github.io/lutin">lutin</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ewol">ewol</a></li>
|
||||
<li><a href="http://atria-soft.github.io/echrono">echrono</a></li>
|
||||
<li><a href="http://atria-soft.github.io/etk">etk</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ejson">ejson</a></li>
|
||||
<li><a href="http://atria-soft.github.io/exml">exml</a></li>
|
||||
<li><a href="http://atria-soft.github.io/esvg">esvg</a></li>
|
||||
<li><a href="http://atria-soft.github.io/egami">egami</a></li>
|
||||
<li><a href="http://atria-soft.github.io/gale">gale</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ege">ege</a></li>
|
||||
<li><a href="http://atria-soft.github.io/elog">elog</a></li>
|
||||
<li><a href="http://atria-soft.github.io/ememory">ememory</a></li>
|
||||
<li><a href="http://atria-soft.github.io/enet">enet</a></li>
|
||||
<li><a href="http://atria-soft.github.io/eproperty">eproperty</a></li>
|
||||
<li><a href="http://atria-soft.github.io/esignal">esignal</a></li>
|
||||
<li><a href="http://atria-soft.github.io/etranslate">etranslate</a></li>
|
||||
<li><a href="http://atria-soft.github.io/zeus">zeus</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-ess">audio-ess</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio">audio</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-drain">audio-drain</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-orchestra">audio-orchestra</a></li>
|
||||
<li><a href="http://musicdsp.github.io/audio-river">audio-river</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<div id="search-box" class="input-group">
|
||||
<div class="input-group-btn">
|
||||
<button aria-expanded="false" type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-search"></span>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li><a href="#">All</a></li>
|
||||
<li><a href="#">Classes</a></li>
|
||||
<li><a href="#">Namespaces</a></li>
|
||||
<li><a href="#">Files</a></li>
|
||||
<li><a href="#">Functions</a></li>
|
||||
<li><a href="#">Variables</a></li>
|
||||
<li><a href="#">Typedefs</a></li>
|
||||
<li><a href="#">Enumerations</a></li>
|
||||
<li><a href="#">Enumerator</a></li>
|
||||
<li><a href="#">Friends</a></li>
|
||||
<li><a href="#">Macros</a></li>
|
||||
<li><a href="#">Pages</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<button id="search-close" type="button" class="close" aria-label="Close">
|
||||
<span aria-hidden="true"></span>
|
||||
</button>
|
||||
<input id="search-field" class="form-control" accesskey="S" onkeydown="searchBox.OnSearchFieldChange(event);" placeholder="Search ..." type="text">
|
||||
</div>
|
||||
</div><!--/.nav-collapse -->
|
||||
</div>
|
||||
</nav>
|
||||
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||
<div class="content" id="content">
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-sm-12 panel panel-default" style="padding-bottom: 15px;">
|
||||
<div style="margin-bottom: 15px;margin-top: 60px;">
|
||||
<!-- end header part -->
|
||||
<!-- Generated by Doxygen 1.8.12 -->
|
||||
<script type="text/javascript">
|
||||
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
||||
</script>
|
||||
<script type="text/javascript" src="menudata.js"></script>
|
||||
<script type="text/javascript" src="menu.js"></script>
|
||||
<script type="text/javascript">
|
||||
$(function() {
|
||||
initMenu('',true,false,'search.php','Search');
|
||||
$(document).ready(function() { init_search(); });
|
||||
});
|
||||
</script>
|
||||
<div id="main-nav"></div>
|
||||
</div><!-- top -->
|
||||
<!-- window showing the filter options -->
|
||||
<div id="MSearchSelectWindow"
|
||||
onmouseover="return searchBox.OnSearchSelectShow()"
|
||||
onmouseout="return searchBox.OnSearchSelectHide()"
|
||||
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
||||
</div>
|
||||
|
||||
<!-- iframe showing the search results (closed by default) -->
|
||||
<div id="MSearchResultsWindow">
|
||||
<iframe src="javascript:void(0)" frameborder="0"
|
||||
name="MSearchResults" id="MSearchResults">
|
||||
</iframe>
|
||||
</div>
|
||||
|
||||
<div class="header">
|
||||
<div class="headertitle">
|
||||
<div class="title">Related Pages</div> </div>
|
||||
</div><!--header-->
|
||||
<div class="contents">
|
||||
<div class="textblock">Here is a list of all related documentation pages:</div><div class="directory">
|
||||
<table class="directory">
|
||||
<tr id="row_0_" class="even"><td class="entry"><span style="width:16px;display:inline-block;"> </span><a class="el" href="audio_orchestra_build.html" target="_self">Build lib & build sample</a></td><td class="desc"></td></tr>
|
||||
</table>
|
||||
</div><!-- directory -->
|
||||
</div><!-- contents -->
|
||||
<!-- HTML footer for doxygen 1.8.8-->
|
||||
<!-- start footer part -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr class="footer"/><address class="footer"><small>
|
||||
Generated on Mon Oct 24 2016 15:35:48 for Orchestra: audio interface wrapper by  <a href="http://www.doxygen.org/index.html">
|
||||
<img class="footer" src="doxygen.png" alt="doxygen"/>
|
||||
</a> 1.8.12
|
||||
</small></address>
|
||||
</body>
|
||||
</html>
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_0.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,21 +0,0 @@
|
||||
var searchData=
|
||||
[
|
||||
['a',['a',['http://atria-soft.github.io/etk/classetk_1_1_color.html#a772e2882d3a9f91c6f73c0c70c8f3130',1,'etk::Color']]],
|
||||
['absolute',['absolute',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a0f1734db865e5a9c69d896bc237de133',1,'etk::Vector2D::absolute()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a0f1734db865e5a9c69d896bc237de133',1,'Vector2D< int32_t >::absolute()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a0f1734db865e5a9c69d896bc237de133',1,'Vector2D< uint32_t >::absolute()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a5b9733cd0928920ccc8e34d89e980b82',1,'etk::Vector3D::absolute()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#ab8a9feace5794c5a8a02e4b0e124408a',1,'etk::Vector4D::absolute()']]],
|
||||
['add',['add',['http://atria-soft.github.io/etk/classetk_1_1_hash.html#a723e93ae06d3d612dc4ebf2e1e7ffd5a',1,'etk::Hash']]],
|
||||
['aliceblue',['aliceBlue',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#adcf86ef9c7918dcb094a0783761899f1',1,'etk::color']]],
|
||||
['angle',['angle',['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a3b403b529d49082265f3655aff656a7e',1,'etk::Vector3D']]],
|
||||
['antiquewhite',['antiqueWhite',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a88abb6eca9c1ba0f346fb697683fa836',1,'etk::color']]],
|
||||
['applyscalerotation',['applyScaleRotation',['http://atria-soft.github.io/etk/classetk_1_1_matrix2.html#aaafd3d4f83d6fd021b76a54f6a31b010',1,'etk::Matrix2']]],
|
||||
['aqua',['aqua',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a2cef110e71ce12876fcfd6605e57f716',1,'etk::color']]],
|
||||
['aquamarine',['aquamarine',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a8b69f67ed3e2db9915acde652a1cff80',1,'etk::color']]],
|
||||
['archive',['Archive',['http://atria-soft.github.io/etk/classetk_1_1_archive.html',1,'etk']]],
|
||||
['archive',['Archive',['http://atria-soft.github.io/etk/classetk_1_1_archive.html#a5991c05535749c9ed04eeec185f675ac',1,'etk::Archive']]],
|
||||
['archive_2ehpp',['Archive.hpp',['http://atria-soft.github.io/etk/__archive__8hpp.html',1,'']]],
|
||||
['archivecontent',['ArchiveContent',['http://atria-soft.github.io/etk/classetk_1_1_archive_content.html',1,'etk']]],
|
||||
['archivecontent',['ArchiveContent',['http://atria-soft.github.io/etk/classetk_1_1_archive_content.html#aac29f8265fa496ca9576f21e13a704d4',1,'etk::ArchiveContent']]],
|
||||
['audio',['audio',['http://musicdsp.github.io/audio/namespaceaudio.html',1,'']]],
|
||||
['avg',['avg',['http://atria-soft.github.io/etk/namespaceetk.html#a4397d293209affffd0c2f6832ebe2aea',1,'etk']]],
|
||||
['azure',['azure',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a51cb04e4a5b927ec82ceef2676b781f7',1,'etk::color']]],
|
||||
['audio_2dorchestra_20library',['AUDIO-ORCHESTRA library',['../index.html',1,'']]]
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_1.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,18 +0,0 @@
|
||||
var searchData=
|
||||
[
|
||||
['build_20lib_20_26_20build_20sample',['Build lib & build sample',['http://musicdsp.github.io/audio/audio_build.html',1,'']]],
|
||||
['build_20lib_20_26_20build_20sample',['Build lib & build sample',['../audio_orchestra_build.html',1,'']]],
|
||||
['b',['b',['http://atria-soft.github.io/etk/classetk_1_1_color.html#ac6be77ac33983d040a2ede58bc631d94',1,'etk::Color']]],
|
||||
['basenoise',['BaseNoise',['http://atria-soft.github.io/etk/classetk_1_1_base_noise.html',1,'etk']]],
|
||||
['basenoise',['BaseNoise',['http://atria-soft.github.io/etk/classetk_1_1_base_noise.html#ad5cbfcc2d967af185c264744de04cf15',1,'etk::BaseNoise']]],
|
||||
['beige',['beige',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a68244b2fa52245487cec1154155d0e03',1,'etk::color']]],
|
||||
['bisque',['bisque',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#ad03e04b97263a2c64dedfc405ff983ee',1,'etk::color']]],
|
||||
['black',['black',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a4198b330ccb2e9008665733eee338f73',1,'etk::color']]],
|
||||
['blanchedalmond',['blanchedAlmond',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a12e8ba075411585a68aece7d0fead4cc',1,'etk::color']]],
|
||||
['blue',['blue',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a50f114c6849684e9984ae1322493572c',1,'etk::color']]],
|
||||
['blueviolet',['blueViolet',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#ac91bcec9a0a115d1070397f86cfdee4d',1,'etk::color']]],
|
||||
['brown',['brown',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#af3dff0347662115abb89c6ddb8447227',1,'etk::color']]],
|
||||
['burlywood',['burlyWood',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a1920dd335710c842ea4706e2383ef784',1,'etk::color']]],
|
||||
['build_20lib_20_26_20build_20sample',['Build lib & build sample',['http://atria-soft.github.io/elog/elog_build.html',1,'']]],
|
||||
['build_20lib_20_26_20build_20sample',['Build lib & build sample',['http://atria-soft.github.io/etk/etk_build.html',1,'']]]
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_10.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,72 +0,0 @@
|
||||
var searchData=
|
||||
[
|
||||
['saddlebrown',['saddleBrown',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a5407ca00d7f7bf3815a72616e0be95ae',1,'etk::color']]],
|
||||
['safenormalize',['safeNormalize',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a245ccd3b57812316fc1ec98ea5c19434',1,'etk::Vector2D::safeNormalize()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a245ccd3b57812316fc1ec98ea5c19434',1,'Vector2D< int32_t >::safeNormalize()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a245ccd3b57812316fc1ec98ea5c19434',1,'Vector2D< uint32_t >::safeNormalize()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#abee6d22d509043f24a5aedb208ba1019',1,'etk::Vector3D::safeNormalize()']]],
|
||||
['salmon',['salmon',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#ad324737686a8c6ec9208a93e727710d8',1,'etk::color']]],
|
||||
['sandybrown',['sandyBrown',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#affd1d87686e7d4fb1a720d4cb5c354cb',1,'etk::color']]],
|
||||
['scale',['scale',['http://atria-soft.github.io/etk/classetk_1_1_matrix2.html#aacc34d6c0be39b22fed735cd09ffed84',1,'etk::Matrix2::scale(const vec2 &_vect)'],['http://atria-soft.github.io/etk/classetk_1_1_matrix2.html#adaa317393ef799d0ab49c3b10cf47231',1,'etk::Matrix2::scale(float _value)'],['http://atria-soft.github.io/etk/classetk_1_1_matrix4.html#aa3121f90430c2e2d80bc967d4b94c114',1,'etk::Matrix4::scale(const vec3 &_vect)'],['http://atria-soft.github.io/etk/classetk_1_1_matrix4.html#a41eb56d343978f32caa64dfda50cd6a5',1,'etk::Matrix4::scale(float _sx, float _sy, float _sz)']]],
|
||||
['seagreen',['seaGreen',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a3d3d8140130f2383e7740b4cea443470',1,'etk::color']]],
|
||||
['seashell',['seaShell',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a6b50105504f9be5dcf7ae59cbb115051',1,'etk::color']]],
|
||||
['seeknode',['seekNode',['http://atria-soft.github.io/etk/namespaceetk.html#a4a0133c254ab2433999c1b61fd9d993e',1,'etk']]],
|
||||
['seeknode_5fcurrent',['seekNode_current',['http://atria-soft.github.io/etk/namespaceetk.html#a4a0133c254ab2433999c1b61fd9d993ea8da2a40c899dc80a97a96999766d1598',1,'etk']]],
|
||||
['seeknode_5fend',['seekNode_end',['http://atria-soft.github.io/etk/namespaceetk.html#a4a0133c254ab2433999c1b61fd9d993ea981349cc2910e974472575409d19f0b6',1,'etk']]],
|
||||
['seeknode_5fstart',['seekNode_start',['http://atria-soft.github.io/etk/namespaceetk.html#a4a0133c254ab2433999c1b61fd9d993ea9019d83f9a109a54ab84067c2aa8abcd',1,'etk']]],
|
||||
['select',['select',['http://atria-soft.github.io/etk/classetk_1_1_matrix.html#a1c8f1bb6f8d14c0fb9d4d39dac67b07b',1,'etk::Matrix']]],
|
||||
['set',['set',['http://atria-soft.github.io/etk/classetk_1_1_color.html#a0955ac7d80e3886afa872d47e0cc1415',1,'etk::Color::set(MY_TYPE _r, MY_TYPE _g, MY_TYPE _b, MY_TYPE _a)'],['http://atria-soft.github.io/etk/classetk_1_1_color.html#a0f663138f780f134ae07957f5a9fef57',1,'etk::Color::set(MY_TYPE _r, MY_TYPE _g, MY_TYPE _b)'],['http://atria-soft.github.io/etk/classetk_1_1_color.html#a7de7eef4b78f10829066af98be02f27b',1,'etk::Color::set(MY_TYPE _r, MY_TYPE _g)'],['http://atria-soft.github.io/etk/classetk_1_1_color.html#a5063a9ee59f18fbeb7172f833617d8eb',1,'etk::Color::set(MY_TYPE _r)'],['http://atria-soft.github.io/etk/classetk_1_1_hash.html#af372b733bfbccd0d67f4df1fbfb62ad7',1,'etk::Hash::set()']]],
|
||||
['seta',['setA',['http://atria-soft.github.io/etk/classetk_1_1_color.html#a1d24c054b6d64d2a73c6cef57d91c31a',1,'etk::Color']]],
|
||||
['setargzero',['setArgZero',['http://atria-soft.github.io/etk/namespaceetk.html#a5eda91763c9f02f0e7e16c099092695d',1,'etk']]],
|
||||
['setb',['setB',['http://atria-soft.github.io/etk/classetk_1_1_color.html#ae8078ca64701dbc1b5080589037743f1',1,'etk::Color']]],
|
||||
['setbacktrace',['setBackTrace',['http://atria-soft.github.io/elog/namespaceelog.html#aae6ff218b5e851513cfc29d030b865fb',1,'elog']]],
|
||||
['setbasefoldercache',['setBaseFolderCache',['http://atria-soft.github.io/etk/namespaceetk.html#a6cdcbe0aeba288278c89a995481b9e6f',1,'etk']]],
|
||||
['setbasefolderdata',['setBaseFolderData',['http://atria-soft.github.io/etk/namespaceetk.html#ab8546560f91d95e2df5f176f5ec0fc99',1,'etk']]],
|
||||
['setbasefolderdatauser',['setBaseFolderDataUser',['http://atria-soft.github.io/etk/namespaceetk.html#a91fb8f53bc0d3ad4ed2061b3f5af7734',1,'etk']]],
|
||||
['setcallbacklog',['setCallbackLog',['http://atria-soft.github.io/elog/namespaceelog.html#a8c02ad11df203c22c7e65c759b43efdd',1,'elog']]],
|
||||
['setcolor',['setColor',['http://atria-soft.github.io/elog/namespaceelog.html#a157a0ce2993c115906b8a2607f6a9133',1,'elog']]],
|
||||
['setfrompoints',['setFromPoints',['http://atria-soft.github.io/etk/classetk_1_1_plane.html#a69b4871efd25fa204a3917360bfb8cc9',1,'etk::Plane']]],
|
||||
['setfunction',['setFunction',['http://atria-soft.github.io/elog/namespaceelog.html#aed76a2bba4f8c0f51633fa64ab08362d',1,'elog']]],
|
||||
['setg',['setG',['http://atria-soft.github.io/etk/classetk_1_1_color.html#a724b243ffc1ba471eab6b04f6ca6ecd4',1,'etk::Color']]],
|
||||
['setgroupreadable',['setGroupReadable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#acca31813653f621d4859d5c837f057a5',1,'etk::FSNodeRight']]],
|
||||
['setgrouprunable',['setGroupRunable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#a5184205ed51108dd9bf3ed4ad141588e',1,'etk::FSNodeRight']]],
|
||||
['setgroupwritable',['setGroupWritable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#acc834eeef2e84b9e7cceac38b3a59389',1,'etk::FSNodeRight']]],
|
||||
['setintercept',['setIntercept',['http://atria-soft.github.io/etk/classetk_1_1_plane.html#a691582e68a6ee38b0c7c9ccf2a6734f3',1,'etk::Plane']]],
|
||||
['setinterpolate3',['setInterpolate3',['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a3e59820b3cc3f9138e69d8aee9a448c8',1,'etk::Vector3D']]],
|
||||
['setlevel',['setLevel',['http://atria-soft.github.io/elog/namespaceelog.html#a3afe4089acb36e88d7266c1ce85ddc7b',1,'elog::setLevel(const std::string &_name, enum elog::level _level)'],['http://atria-soft.github.io/elog/namespaceelog.html#a423b95c78b78e98de35c8f176b9efbdc',1,'elog::setLevel(int32_t _id, enum elog::level _level)'],['http://atria-soft.github.io/elog/namespaceelog.html#a600189d0be9885f63d651201ab0c3688',1,'elog::setLevel(enum elog::level _level)']]],
|
||||
['setlibname',['setLibName',['http://atria-soft.github.io/elog/namespaceelog.html#a98f690a8538d4726fa0060331e021a08',1,'elog']]],
|
||||
['setline',['setLine',['http://atria-soft.github.io/elog/namespaceelog.html#a2591d4ba7e3136ff84c0b81289000b79',1,'elog']]],
|
||||
['setloginfile',['setLogInFile',['http://atria-soft.github.io/elog/namespaceelog.html#a78083b9d6ef033e329b788f8fa22f3f3',1,'elog']]],
|
||||
['setmax',['setMax',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a72ae52d19423c46bad955ad1a9f59041',1,'etk::Vector2D::setMax()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a72ae52d19423c46bad955ad1a9f59041',1,'Vector2D< int32_t >::setMax()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a72ae52d19423c46bad955ad1a9f59041',1,'Vector2D< uint32_t >::setMax()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a7b9a94f71854f5ad89ef23ef22dcb321',1,'etk::Vector3D::setMax()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a2469c42527ead691f479a9a573709e5f',1,'etk::Vector4D::setMax()']]],
|
||||
['setmin',['setMin',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#aa087eeec653b538d166c0d2794737fb1',1,'etk::Vector2D::setMin()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#aa087eeec653b538d166c0d2794737fb1',1,'Vector2D< int32_t >::setMin()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#aa087eeec653b538d166c0d2794737fb1',1,'Vector2D< uint32_t >::setMin()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a7c2e3d0042a62791b1c653d5081577c2',1,'etk::Vector3D::setMin()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#aa647808a65613af0e1e757f27444f0a6',1,'etk::Vector4D::setMin()']]],
|
||||
['setname',['setName',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#a6e787e7f3148dae0c74139be7b05ab43',1,'etk::FSNode']]],
|
||||
['setnormal',['setNormal',['http://atria-soft.github.io/etk/classetk_1_1_plane.html#a202b3335b2b71cc84726a1b57b8e1e70',1,'etk::Plane']]],
|
||||
['setotherreadable',['setOtherReadable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#a6ad46a56d871f5925a826a6fd3071b78',1,'etk::FSNodeRight']]],
|
||||
['setotherrunable',['setOtherRunable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#a290708c849f5b58714dad5a1926cfe1c',1,'etk::FSNodeRight']]],
|
||||
['setotherwritable',['setOtherWritable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#a931050b25db28423f1a2899f8ec188a0',1,'etk::FSNodeRight']]],
|
||||
['setr',['setR',['http://atria-soft.github.io/etk/classetk_1_1_color.html#a96c8b12779776562c2fa0dfdc4d1b242',1,'etk::Color']]],
|
||||
['setright',['setRight',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#a65bce1c8887edad87a90c8c7ffb861d3',1,'etk::FSNode']]],
|
||||
['setthreadid',['setThreadId',['http://atria-soft.github.io/elog/namespaceelog.html#a9b835d4980949026a8883570ea3837af',1,'elog']]],
|
||||
['setthreadnameenable',['setThreadNameEnable',['http://atria-soft.github.io/elog/namespaceelog.html#ae64b5abf2ea03562679668e6242c49a2',1,'elog']]],
|
||||
['settime',['setTime',['http://atria-soft.github.io/elog/namespaceelog.html#a15e30e61e8db5a43e72358d2c02be6a4',1,'elog']]],
|
||||
['setuserreadable',['setUserReadable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#acadd7b9c2c632f9805569ff4f592bda9',1,'etk::FSNodeRight']]],
|
||||
['setuserrunable',['setUserRunable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#a0ee76ec4897c406ab67ea25659953070',1,'etk::FSNodeRight']]],
|
||||
['setuserwritable',['setUserWritable',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node_right.html#a9e5e2e4c7926c22101e6955b3d8c9139',1,'etk::FSNodeRight']]],
|
||||
['setvalue',['setValue',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ade86675814738c6b7a6a797ee128a2b2',1,'etk::Vector2D::setValue()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ade86675814738c6b7a6a797ee128a2b2',1,'Vector2D< int32_t >::setValue()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ade86675814738c6b7a6a797ee128a2b2',1,'Vector2D< uint32_t >::setValue()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a96d02449aaa2dfeb4e60320da667ab92',1,'etk::Vector3D::setValue()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a9b164290093d948905fab0f56fbe22fc',1,'etk::Vector4D::setValue()']]],
|
||||
['setw',['setW',['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a1750c9d1b91d67b8b2bc9d0cce759944',1,'etk::Vector4D']]],
|
||||
['setx',['setX',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ae2acd7c10cdd510ce23ff11839c95c04',1,'etk::Vector2D::setX()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ae2acd7c10cdd510ce23ff11839c95c04',1,'Vector2D< int32_t >::setX()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ae2acd7c10cdd510ce23ff11839c95c04',1,'Vector2D< uint32_t >::setX()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#ab7ab9d9ce1138ffafebaff3001bb7d29',1,'etk::Vector3D::setX()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a238d966b077394ff118f2088479fb620',1,'etk::Vector4D::setX()']]],
|
||||
['sety',['setY',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a35a3f35ed049b7193ca67ea815efd465',1,'etk::Vector2D::setY()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a35a3f35ed049b7193ca67ea815efd465',1,'Vector2D< int32_t >::setY()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a35a3f35ed049b7193ca67ea815efd465',1,'Vector2D< uint32_t >::setY()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a10c41fb516fb33ef56201f06992462d1',1,'etk::Vector3D::setY()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a7489a0c8d592c9464a8e378bbb7e570e',1,'etk::Vector4D::setY()']]],
|
||||
['setz',['setZ',['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a9a5c1d69fd9066daae0a759831ba0e30',1,'etk::Vector3D::setZ()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#ae5bbc387ea4199ea535d4d033cfc40d1',1,'etk::Vector4D::setZ()']]],
|
||||
['setzero',['setZero',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ab2e921e0009f0e0de78d06d16f6a78e0',1,'etk::Vector2D::setZero()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ab2e921e0009f0e0de78d06d16f6a78e0',1,'Vector2D< int32_t >::setZero()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ab2e921e0009f0e0de78d06d16f6a78e0',1,'Vector2D< uint32_t >::setZero()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a7ddb707a7a1609bcbd8c092186a6db19',1,'etk::Vector3D::setZero()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a978b0511ade11701ffdbd7974de6932e',1,'etk::Vector4D::setZero()']]],
|
||||
['sienna',['sienna',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a0a8eaf790795f7b5fc63c81ade8652ce',1,'etk::color']]],
|
||||
['silver',['silver',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#aca25e934d9d1ac1538a4a0c7011c6d0c',1,'etk::color']]],
|
||||
['simplifypath',['simplifyPath',['http://atria-soft.github.io/etk/namespaceetk.html#a0087446ff0e9b533ea70b3043ae2addc',1,'etk']]],
|
||||
['size',['size',['http://atria-soft.github.io/etk/classetk_1_1_archive.html#a17d06497d98be15f6080cf84010d35a0',1,'etk::Archive::size()'],['http://atria-soft.github.io/etk/classetk_1_1_archive_content.html#a36dc83c35ebdacdce11e04dbcba4334c',1,'etk::ArchiveContent::size()'],['http://atria-soft.github.io/etk/classetk_1_1_hash.html#a4d639eb19c25b1ff76d34c225a132deb',1,'etk::Hash::size()']]],
|
||||
['skyblue',['skyBlue',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a1576fd8ed2c3fe5ed5a10f8147d0ed1d',1,'etk::color']]],
|
||||
['slateblue',['slateBlue',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a4f605302a82a6173de726e797c3edf0d',1,'etk::color']]],
|
||||
['slategray',['slateGray',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a5d3c48d14e696bc1b8d9d43158dfa0b2',1,'etk::color']]],
|
||||
['slategrey',['slateGrey',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a9cefc035f467790176ba159bb6255c6e',1,'etk::color']]],
|
||||
['snow',['snow',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#ae312c38fc6be5178a4ff63921f162723',1,'etk::color']]],
|
||||
['space',['Space',['http://atria-soft.github.io/etk/namespaceu32char.html#a7a114cf0424bb72fd7f3f10c9cd017e8',1,'u32char']]],
|
||||
['springgreen',['springGreen',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#ab3b6e2028b00791f15ddff7f9a1fe703',1,'etk::color']]],
|
||||
['stdtools_2ehpp',['stdTools.hpp',['http://atria-soft.github.io/etk/std__tools__8hpp.html',1,'']]],
|
||||
['steelblue',['steelBlue',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a9162b466a59a0bbe420b49c565e9dd6f',1,'etk::color']]],
|
||||
['suppress',['Suppress',['http://atria-soft.github.io/etk/namespaceu32char.html#a9cff086787b8b0321e36251a27c40321',1,'u32char']]]
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_11.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,36 +0,0 @@
|
||||
var searchData=
|
||||
[
|
||||
['tutorials',['Tutorials',['http://atria-soft.github.io/elog/elog_tutorial.html',1,'']]],
|
||||
['tabulation',['Tabulation',['http://atria-soft.github.io/etk/namespaceu32char.html#ad7a0c42ea443e20bfceb69f863bebc6a',1,'u32char']]],
|
||||
['tan',['tan',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a923b2869775837088eabdb48681f4b1e',1,'etk::color']]],
|
||||
['teal',['teal',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a9b28dace6aa8c81c0c59a7343875d2b5',1,'etk::color']]],
|
||||
['theoricfirst',['theoricFirst',['http://atria-soft.github.io/etk/namespaceutf8.html#a52043c6c7cf75da5f8e8812ffb4ffc1c',1,'utf8']]],
|
||||
['theoriclen',['theoricLen',['http://atria-soft.github.io/etk/namespaceutf8.html#ad408da64c12fe3345b9576ab487bd7e3',1,'utf8']]],
|
||||
['thistle',['thistle',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a729d8532a3b7c147fcaa726ce2d887b8',1,'etk::color']]],
|
||||
['time_2ehpp',['Time.hpp',['http://musicdsp.github.io/audio/__time__8hpp.html',1,'']]],
|
||||
['timeaccessed',['timeAccessed',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#a43c3b946ef91744dd2991734166c1d87',1,'etk::FSNode']]],
|
||||
['timeaccessedstring',['timeAccessedString',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#a17022f6598927b1b9f169cbcd99099e6',1,'etk::FSNode']]],
|
||||
['timecreated',['timeCreated',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#a46fe9a1916400ca932d31a847dff0f21',1,'etk::FSNode']]],
|
||||
['timecreatedstring',['timeCreatedString',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#a30a497f2d095469b5846756a1b51a749',1,'etk::FSNode']]],
|
||||
['timemodified',['timeModified',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#afa84341a6764252f5fb70eb48540f496',1,'etk::FSNode']]],
|
||||
['timemodifiedstring',['timeModifiedString',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#a3cdee551ca80df9597a408b42b4f7210',1,'etk::FSNode']]],
|
||||
['to_5fstring',['to_string',['http://atria-soft.github.io/etk/namespaceetk.html#a48ed31a00f989f5b188d7254e6945a74',1,'etk::to_string(const TYPE &_variable)'],['http://atria-soft.github.io/etk/namespaceetk.html#a17aa4febea213096442bcb8e7ca80805',1,'etk::to_string(const std::vector< TYPE > &_list)']]],
|
||||
['toint',['toInt',['http://atria-soft.github.io/etk/namespaceu32char.html#afc40d527459e3869ea8dc54d3b5ef225',1,'u32char']]],
|
||||
['tomato',['tomato',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a9f3fe621ef99b1b452a5a11af1a06ae0',1,'etk::color']]],
|
||||
['tool_2ehpp',['tool.hpp',['http://atria-soft.github.io/etk/tool__8hpp.html',1,'']]],
|
||||
['touch',['touch',['http://atria-soft.github.io/etk/classetk_1_1_f_s_node.html#a6fd01aeb7f84399ad99573e0a7e2f8fc',1,'etk::FSNode']]],
|
||||
['translate',['translate',['http://atria-soft.github.io/etk/classetk_1_1_matrix2.html#abd22ba1cbe8dc53c0446abcb55d8551a',1,'etk::Matrix2::translate()'],['http://atria-soft.github.io/etk/classetk_1_1_matrix4.html#aa6cd07f3a802c5a57bddbf5a6db95c4d',1,'etk::Matrix4::translate()']]],
|
||||
['transpose',['transpose',['http://atria-soft.github.io/etk/classetk_1_1_matrix.html#ab05c8b14ec68367d0391c23b77870a3b',1,'etk::Matrix::transpose()'],['http://atria-soft.github.io/etk/classetk_1_1_matrix4.html#a8214b2300ebdc4b42bde1efe93e84fae',1,'etk::Matrix4::transpose()']]],
|
||||
['triple',['triple',['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#af1e591712d4a15bd21ad6fd22d72df97',1,'etk::Vector3D']]],
|
||||
['turquoise',['turquoise',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a8162f21fcdb858a4c5017a20db4c5830',1,'etk::color']]],
|
||||
['typenode',['typeNode',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8',1,'etk']]],
|
||||
['typenode_5fblock',['typeNode_block',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8a18f1c41a5c9bc4842a512954af23d630',1,'etk']]],
|
||||
['typenode_5fcharacter',['typeNode_character',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8a07f61c5191a0e393871ecf69f4f32eed',1,'etk']]],
|
||||
['typenode_5ffifo',['typeNode_fifo',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8af5a5a8cef27d1c2abf4c6b7b9a893890',1,'etk']]],
|
||||
['typenode_5ffile',['typeNode_file',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8a4bb596537f408d12f89da085cac752c6',1,'etk']]],
|
||||
['typenode_5ffolder',['typeNode_folder',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8a67fbbfd55ff1568df12ca9719bc73680',1,'etk']]],
|
||||
['typenode_5flink',['typeNode_link',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8a73f8fdd1c9f08183be017f372935cf14',1,'etk']]],
|
||||
['typenode_5fsocket',['typeNode_socket',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8a9b46f1f9d230b9490b2c17af379c61bc',1,'etk']]],
|
||||
['typenode_5funknow',['typeNode_unknow',['http://atria-soft.github.io/etk/namespaceetk.html#a99c2dd948d6da85ed816fa0c267862e8a4c85a6b7dccfd424a20b383e5dbe63bf',1,'etk']]],
|
||||
['types_2ehpp',['types.hpp',['http://atria-soft.github.io/etk/types__8hpp.html',1,'(Global Namespace)'],['http://musicdsp.github.io/audio/types__8hpp.html',1,'(Global Namespace)']]]
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_12.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,6 +0,0 @@
|
||||
var searchData=
|
||||
[
|
||||
['u32char',['u32char',['http://atria-soft.github.io/etk/namespaceu32char.html',1,'']]],
|
||||
['unsetloginfile',['unsetLogInFile',['http://atria-soft.github.io/elog/namespaceelog.html#a496120feb0c59449a46057559c6c8a1a',1,'elog']]],
|
||||
['utf8',['utf8',['http://atria-soft.github.io/etk/namespaceutf8.html',1,'']]]
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_13.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,15 +0,0 @@
|
||||
var searchData=
|
||||
[
|
||||
['vector2d',['Vector2D',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html',1,'etk']]],
|
||||
['vector2d',['Vector2D',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a09b5e26eacb50a8059d0e0c65405eb82',1,'etk::Vector2D::Vector2D(T _xxx, T _yyy)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#aaece962e3caa1d70afe0b1682ce8212e',1,'etk::Vector2D::Vector2D(const Vector2D< double > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#acab36ec2f778107bc89f4e5c9463191b',1,'etk::Vector2D::Vector2D(const Vector2D< float > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ab07ef273334d86b96dd13a4ce4c19137',1,'etk::Vector2D::Vector2D(const Vector2D< int32_t > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a187bb96fc68cb5d5dadc99f573674b98',1,'etk::Vector2D::Vector2D(const std::string &_str)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a09b5e26eacb50a8059d0e0c65405eb82',1,'Vector2D< int32_t >::Vector2D(int32_t _xxx, int32_t _yyy)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#aaece962e3caa1d70afe0b1682ce8212e',1,'Vector2D< int32_t >::Vector2D(const Vector2D< double > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#acab36ec2f778107bc89f4e5c9463191b',1,'Vector2D< int32_t >::Vector2D(const Vector2D< float > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ab07ef273334d86b96dd13a4ce4c19137',1,'Vector2D< int32_t >::Vector2D(const Vector2D< int32_t > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a187bb96fc68cb5d5dadc99f573674b98',1,'Vector2D< int32_t >::Vector2D(const std::string &_str)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a09b5e26eacb50a8059d0e0c65405eb82',1,'Vector2D< uint32_t >::Vector2D(uint32_t _xxx, uint32_t _yyy)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#aaece962e3caa1d70afe0b1682ce8212e',1,'Vector2D< uint32_t >::Vector2D(const Vector2D< double > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#acab36ec2f778107bc89f4e5c9463191b',1,'Vector2D< uint32_t >::Vector2D(const Vector2D< float > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#ab07ef273334d86b96dd13a4ce4c19137',1,'Vector2D< uint32_t >::Vector2D(const Vector2D< int32_t > &_obj)'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a187bb96fc68cb5d5dadc99f573674b98',1,'Vector2D< uint32_t >::Vector2D(const std::string &_str)']]],
|
||||
['vector2d_2ehpp',['Vector2D.hpp',['http://atria-soft.github.io/etk/__vector2__d__8hpp.html',1,'']]],
|
||||
['vector2d_3c_20int32_5ft_20_3e',['Vector2D< int32_t >',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html',1,'']]],
|
||||
['vector2d_3c_20uint32_5ft_20_3e',['Vector2D< uint32_t >',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html',1,'']]],
|
||||
['vector3d',['Vector3D',['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html',1,'etk']]],
|
||||
['vector3d',['Vector3D',['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a409169c1781cae5220b9f7bd078e05d9',1,'etk::Vector3D::Vector3D()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#a7f5d02301a551e7f686092d7b9a5b269',1,'etk::Vector3D::Vector3D(const T &_xxx, const T &_yyy, const T &_zzz)']]],
|
||||
['vector3d_2ehpp',['Vector3D.hpp',['http://atria-soft.github.io/etk/__vector3__d__8hpp.html',1,'']]],
|
||||
['vector4d',['Vector4D',['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html',1,'etk']]],
|
||||
['vector4d',['Vector4D',['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a0e140dec4eca4f3695f19fb92dc3e1ae',1,'etk::Vector4D::Vector4D()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a7a41fd47b438cc43849a2b2c0f308db2',1,'etk::Vector4D::Vector4D(const T &_xxx, const T &_yyy, const T &_zzz, const T &_www)']]],
|
||||
['vector4d_2ehpp',['Vector4D.hpp',['http://atria-soft.github.io/etk/__vector4__d__8hpp.html',1,'']]],
|
||||
['violet',['violet',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#ac86b1f752bb46992b83000f1b48957ec',1,'etk::color']]]
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_14.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,8 +0,0 @@
|
||||
var searchData=
|
||||
[
|
||||
['w',['w',['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a0ede53650faf9183b87a3592e8be142d',1,'etk::Vector4D']]],
|
||||
['wait',['wait',['http://atria-soft.github.io/etk/classetk_1_1_fifo.html#a0693f87b2886e553ccdafdac112ebbd5',1,'etk::Fifo::wait(MY_TYPE &_data)'],['http://atria-soft.github.io/etk/classetk_1_1_fifo.html#aa08e5c57d91bc54ea08f377a6e2653e3',1,'etk::Fifo::wait(MY_TYPE &_data, uint32_t _timeOutInUs)']]],
|
||||
['wheat',['wheat',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a0fee5d2cd67adc3c4a5d820616854cde',1,'etk::color']]],
|
||||
['white',['white',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a6559ba632982f84ab6215281bd431b9c',1,'etk::color']]],
|
||||
['whitesmoke',['whiteSmoke',['http://atria-soft.github.io/etk/namespaceetk_1_1color.html#a1b012cf56fb3a1c63e55aa2d83f7472b',1,'etk::color']]]
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_15.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
@ -1,4 +0,0 @@
|
||||
var searchData=
|
||||
[
|
||||
['x',['x',['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a8409de5d430e5cdcb7326aee94176873',1,'etk::Vector2D::x()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a8409de5d430e5cdcb7326aee94176873',1,'Vector2D< int32_t >::x()'],['http://atria-soft.github.io/etk/classetk_1_1_vector2_d.html#a8409de5d430e5cdcb7326aee94176873',1,'Vector2D< uint32_t >::x()'],['http://atria-soft.github.io/etk/classetk_1_1_vector3_d.html#af2bda50fefea08fb49c04b15a61bcb6a',1,'etk::Vector3D::x()'],['http://atria-soft.github.io/etk/classetk_1_1_vector4_d.html#a98cef087b46916c257dc7b7e39230e74',1,'etk::Vector4D::x()']]]
|
||||
];
|
@ -1,26 +0,0 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<html><head><title></title>
|
||||
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||
<meta name="generator" content="Doxygen 1.8.12"/>
|
||||
<link rel="stylesheet" type="text/css" href="search.css"/>
|
||||
<script type="text/javascript" src="all_16.js"></script>
|
||||
<script type="text/javascript" src="search.js"></script>
|
||||
</head>
|
||||
<body class="SRPage">
|
||||
<div id="SRIndex">
|
||||
<div class="SRStatus" id="Loading">Loading...</div>
|
||||
<div id="SRResults"></div>
|
||||
<script type="text/javascript"><!--
|
||||
createResults();
|
||||
--></script>
|
||||
<div class="SRStatus" id="Searching">Searching...</div>
|
||||
<div class="SRStatus" id="NoMatches">No Matches</div>
|
||||
<script type="text/javascript"><!--
|
||||
document.getElementById("Loading").style.display="none";
|
||||
document.getElementById("NoMatches").style.display="none";
|
||||
var searchResults = new SearchResults("searchResults");
|
||||
searchResults.Search();
|
||||
--></script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user