/
ofApp.cpp
155 lines (126 loc) · 4.88 KB
/
ofApp.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/*
* Copyright (c) 2015 Dan Wilcox <danomatika@gmail.com>
*
* BSD Simplified License.
* For information on usage and redistribution, and for a DISCLAIMER OF ALL
* WARRANTIES, see the file, "LICENSE.txt," in this distribution.
*
* See https://github.com/danomatika/ofxPd for documentation
*
*/
#include "ofApp.h"
//--------------------------------------------------------------
void ofApp::setup() {
ofSetFrameRate(60);
ofSetVerticalSync(true);
//ofSetLogLevel("Pd", OF_LOG_VERBOSE); // see verbose info inside
// the number of libpd ticks per buffer,
// used to compute the audio buffer len: tpb * blocksize (always 64)
#ifdef TARGET_LINUX_ARM
// longer latency for Raspberry PI
int ticksPerBuffer = 32; // 32 * 64 = buffer len of 2048
int numInputs = 0; // no built in mic
#else
int ticksPerBuffer = 8; // 8 * 64 = buffer len of 512
int numInputs = 1;
#endif
int numOutputs = 2;
// setup OF sound stream
ofSoundStreamSetup(numOutputs, numInputs, this, 44100, ofxPd::blockSize()*ticksPerBuffer, 4);
// allocate pd instance handles
pdinstance1 = pdinstance_new();
pdinstance2 = pdinstance_new();
// set a "current" instance before pd.init() or else Pd will make
// an unnecessary third "default" instance
pd_setinstance(pdinstance1);
// setup Pd
//
// set 4th arg to true for queued message passing using an internal ringbuffer,
// this is useful if you need to control where and when the message callbacks
// happen (ie. within a GUI thread)
//
// note: you won't see any message prints until update() is called since
// the queued messages are processed there, this is normal
//
// ... here we'd sure like to be able to have number of channels be
// per-instance. The sample rate is still global within Pd but we might
// also consider relaxing that restrction.
//
if(!pd.init(numOutputs, numInputs, 44100, ticksPerBuffer, false)) {
ofExit(1);
}
pd.setReceiver(this);
// allocate instance output buffers
int bufferSize = numOutputs*ticksPerBuffer*ofxPd::blockSize();
outputBuffer1 = new float[bufferSize];
outputBuffer2 = new float[bufferSize];
memset(outputBuffer1, 0, bufferSize);
memset(outputBuffer2, 0, bufferSize);
pd_setinstance(pdinstance1); // talk to first pd instance
// audio processing on
pd.start();
// open patch
pd.openPatch("test.pd");
pd_setinstance(pdinstance2); // talk to the second pd instance
// audio processing on
pd.start();
// open patch
pd.openPatch("test.pd");
// The following two messages can be sent without setting the pd instance
// and anyhow the symbols are global so they may affect multiple instances.
// However, if the messages change anything in the pd instance structure
// (DSP state; current time; list of all canvases n our instance) those
// changes will apply to the current Pd nstance, so the earlier messages,
// for instance, were sensitive to which was the current one.
//
// Note also that I'm using the fact that $0 is set to 1003, 1004, ...
// as patches are opened, it would be better to open the patches with
// settable $1, etc parameters to openPatch().
// [; pd frequency 220 (
pd << StartMessage() << 440.0f << FinishMessage("1003-frequency", "float");
// [; pd frequency 440 (
pd << StartMessage() << 880.0f << FinishMessage("1004-frequency", "float");
}
//--------------------------------------------------------------
void ofApp::update() {
ofBackground(100, 100, 100);
// since this is a test and we don't know if init() was called with
// queued = true or not, we check it here
if(pd.isQueued()) {
// process any received messages, if you're using the queue
pd.receiveMessages();
}
// run for 1 second and exit
if(ofGetElapsedTimef() > 1.0) {
ofExit(); // exit app
}
}
//--------------------------------------------------------------
void ofApp::draw() {}
//--------------------------------------------------------------
void ofApp::audioReceived(float * input, int bufferSize, int nChannels) {
// process audio input for instance 1
pd_setinstance(pdinstance1);
pd.audioIn(input, bufferSize, nChannels);
// process audio input for instance 2
pd_setinstance(pdinstance2);
pd.audioIn(input, bufferSize, nChannels);
}
//--------------------------------------------------------------
void ofApp::audioRequested(float * output, int bufferSize, int nChannels) {
// process audio output for instance 1
pd_setinstance(pdinstance1);
pd.audioOut(outputBuffer1, bufferSize, nChannels);
// process audio output for instance 2
pd_setinstance(pdinstance2);
pd.audioOut(outputBuffer2, bufferSize, nChannels);
// mix the two instance output buffers together
int size = bufferSize*sizeof(float);
for(int i = 0; i < size; i += sizeof(float)) {
output[i] = (outputBuffer1[i] + outputBuffer2[i]) * 0.5f; // mix
}
}
//--------------------------------------------------------------
void ofApp::print(const std::string& message) {
cout << message << endl;
}