-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathZgnaclInstance.cpp
148 lines (128 loc) · 5.83 KB
/
ZgnaclInstance.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
/*
* Copyright 2011,2012 Martin Roth
*
* This file is part of Cynical.
*
* Cynical is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cynical is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Cynical. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ZgnaclInstance.h"
#include "zgcallback.h"
#define kPlaySoundId "playSound"
#define kStopSoundId "stopSound"
#define kMessageArgumentSeparator ':'
bool ZgnaclInstance::Init(uint32_t argc, const char* argn[], const char* argv[]) {
// Ask the device for an appropriate block size, with a default of 512
blockSize_ = pp::AudioConfig::RecommendSampleFrameCount(PP_AUDIOSAMPLERATE_44100, 512);
audio_ = pp::Audio(this, pp::AudioConfig(this, PP_AUDIOSAMPLERATE_44100, blockSize_),
audioCallback, this);
// create the ZGContext with 0 input and 2 output channels
zgContext_ = zg_context_new(0, 2, blockSize_, 44100.0f, zgCallbackFunction, this);
// TODO(mhroth): initialise the light pipe here
pipe_ = new LightPipe(32);
// kick off the LightPipe reader
zgReadAndProcessPipe(this, 0);
pipeReadIntervalMs = 50; // 50ms default pipe read interval
return true;
}
void ZgnaclInstance::audioCallback(void *samples, uint32_t buffer_size, void *data) {
ZgnaclInstance* zgnaclInstance = reinterpret_cast<ZgnaclInstance*>(data);
// samples are channel interleaved shorts
short *buffer = (short *) samples;
zg_context_process_s(zgnaclInstance->zgContext(), buffer, buffer);
}
void ZgnaclInstance::HandleMessage(const pp::Var& var_message) {
if (!var_message.is_string()) {
return;
}
std::string message = var_message.AsString();
if (message == kPlaySoundId) {
audio_.StartPlayback();
} else if (message == kStopSoundId) {
audio_.StopPlayback();
} else { // process functions with arguments
size_t pos = message.find_first_of(kMessageArgumentSeparator); // find position of first argument
if (pos != string::npos) {
if (!message.compare(0, pos, "newGraph")) {
string graphDesc = message.substr(pos+1, string::npos); // get the graph description
ZGGraph *graph = zg_context_new_graph_from_string(zgContext_, graphDesc.c_str());
if (graph != NULL) {
zg_graph_attach(graph);
PostMessage(pp::Var(reinterpret_cast<int32_t>(graph))); // return the id of the new graph
// NOTE(mhroth): reinterpret_cast<int32_t> could cause problems with 64-bit systems. It
// is intended that this returned value can be used to refer to the specific according to
// its memory address.
} else {
PostMessage(pp::Var("Graph could not be created. Reason unknown."));
}
} else if (!message.compare(0, pos, "sendMessage")) {
// receiver:timestamp:arguments
// "recName:0.0:0 0"
// first argument is receiver
size_t pos2 = message.find_first_of(kMessageArgumentSeparator, pos+1);
string receiverName = message.substr(pos+1, pos2-pos-1);
// second argument is timestamp
size_t pos3 = message.find_first_of(kMessageArgumentSeparator, pos2+1);
string timestamp = message.substr(pos2+1, pos3-pos2-1);
// third argument is message description
string initString = message.substr(pos3+1, string::npos);
// send the message into ZenGarden
zg_context_send_message_from_string(zgContext_, receiverName.c_str(),
strtod(timestamp.c_str(), NULL), initString.c_str());
} else if (!message.compare(0, pos, "registerReceiver")) {
// register an external receiver
string receiverName = message.substr(pos+1, string::npos);
zg_context_register_receiver(zgContext_, receiverName.c_str());
} else if (!message.compare(0, pos, "unregisterReceiver")) {
// unregister an external receiver
string receiverName = message.substr(pos+1, string::npos);
zg_context_unregister_receiver(zgContext_, receiverName.c_str());
} else if (!message.compare(0, pos, "setPipeReadInterval")) {
string interval = message.substr(pos+1, string::npos);
pipeReadIntervalMs = atoi(interval.c_str());
} else {
PostMessage(var_message); // if we mess something up, return the input
}
} else {
PostMessage(var_message); // if we mess something up, return the input
}
}
}
/*
* The Module class. The browser calls the CreateInstance() method to create
* an instance of your NaCl module on the web page. The browser creates a new
* instance for each <embed> tag with type="application/x-nacl".
*/
class ZgnaclModule : public pp::Module {
public:
ZgnaclModule() : pp::Module() {}
virtual ~ZgnaclModule() {}
/// Create and return a ZgnaclInstance object.
/// @param[in] instance The browser-side instance.
/// @return the plugin-side instance.
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new ZgnaclInstance(instance);
}
};
namespace pp {
/// Factory function called by the browser when the module is first loaded.
/// The browser keeps a singleton of this module. It calls the
/// CreateInstance() method on the object you return to make instances. There
/// is one instance per <embed> tag on the page. This is the main binding
/// point for your NaCl module with the browser.
Module* CreateModule() {
return new ZgnaclModule();
}
} // end namespace pp