bumping version to 3.5-rc1
[supercollider.git] / server / supernova / sc / sc_synth.cpp
blobd5be679d859922691f675501d01baf0125ce2094
1 // synth based on supercollider-style synthdef
2 // Copyright (C) 2009, 2010 Tim Blechmann
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; see the file COPYING. If not, write to
16 // the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 // Boston, MA 02111-1307, USA.
19 #include <cstdio>
21 #include <boost/bind.hpp>
23 #include "sc_synth.hpp"
24 #include "sc_ugen_factory.hpp"
25 #include "../server/server.hpp"
27 namespace nova
30 sc_synth::sc_synth(int node_id, sc_synth_prototype_ptr const & prototype):
31 abstract_synth(node_id, prototype), trace(0), unit_buffers(0)
33 World const & world = sc_factory->world;
34 mNode.mWorld = &sc_factory->world;
35 rgen.init((uint32_t)(uint64_t)this);
37 /* initialize sc wrapper class */
38 mRGen = &rgen;
39 mSubsampleOffset = world.mSubsampleOffset;
40 mSampleOffset = world.mSampleOffset;
41 mLocalAudioBusUnit = 0;
42 mLocalControlBusUnit = 0;
44 localBufNum = 0;
45 localMaxBufNum = 0;
47 mNode.mID = node_id;
49 sc_synthdef const & synthdef = *prototype;
51 const size_t parameter_count = synthdef.parameter_count();
52 const size_t constants_count = synthdef.constants.size();
54 /* we allocate one memory chunk */
55 const size_t alloc_size = prototype->memory_requirement();
57 const size_t sample_alloc_size = world.mBufLength * synthdef.buffer_count
58 + vec<float>::size * sizeof(float) /* for alignment */;
60 char * chunk = (char*)rt_pool.malloc(alloc_size + sample_alloc_size*sizeof(sample));
61 if (chunk == NULL)
62 throw std::bad_alloc();
64 /* prepare controls */
65 mNumControls = parameter_count;
66 mControls = (float*)chunk; chunk += sizeof(float) * parameter_count;
67 mControlRates = (int*)chunk; chunk += sizeof(int) * parameter_count;
68 mMapControls = (float**)chunk; chunk += sizeof(float*) * parameter_count;
70 /* initialize controls */
71 for (size_t i = 0; i != parameter_count; ++i) {
72 mControls[i] = synthdef.parameters[i]; /* initial parameters */
73 mMapControls[i] = &mControls[i]; /* map to control values */
74 mControlRates[i] = 0; /* init to 0*/
77 /* allocate constant wires */
78 mWire = (Wire*)chunk; chunk += sizeof(Wire) * constants_count;
79 for (size_t i = 0; i != synthdef.constants.size(); ++i) {
80 Wire * wire = mWire + i;
81 wire->mFromUnit = 0;
82 wire->mCalcRate = 0;
83 wire->mBuffer = 0;
84 wire->mScalarValue = get_constant(i);
87 unit_count = prototype->unit_count();
88 calc_unit_count = prototype->calc_unit_count();
89 units = (Unit**)chunk; chunk += unit_count * sizeof(Unit*);
90 calc_units = (Unit**)chunk; chunk += calc_unit_count * sizeof(Unit*);
91 unit_buffers = (sample*)chunk; chunk += sample_alloc_size*sizeof(sample);
93 const int alignment_mask = vec<float>::size * sizeof(float) - 1;
94 unit_buffers = (sample*) ((size_t(unit_buffers) + alignment_mask) & ~alignment_mask); /* next aligned pointer */
96 /* allocate unit generators */
97 sc_factory->allocate_ugens(synthdef.graph.size());
98 for (size_t i = 0; i != synthdef.graph.size(); ++i) {
99 sc_synthdef::unit_spec_t const & spec = synthdef.graph[i];
100 units[i] = spec.prototype->construct(spec, this, &sc_factory->world, chunk);
103 for (size_t i = 0; i != synthdef.calc_unit_indices.size(); ++i) {
104 int32_t index = synthdef.calc_unit_indices[i];
105 calc_units[i] = units[index];
108 assert((char*)mControls + alloc_size <= chunk); // ensure the memory boundaries
111 namespace
114 void free_ugen(struct Unit * unit)
116 sc_ugen_def * def = reinterpret_cast<sc_ugen_def*>(unit->mUnitDef);
117 def->destruct(unit);
120 } /* namespace */
122 sc_synth::~sc_synth(void)
124 std::for_each(units, units + unit_count, free_ugen);
125 sc_factory->free_ugens(unit_count);
126 rt_pool.free(mControls);
129 void sc_synth::prepare(void)
131 for (size_t i = 0; i != unit_count; ++i) {
132 struct Unit * unit = units[i];
133 sc_ugen_def * def = reinterpret_cast<sc_ugen_def*>(unit->mUnitDef);
134 def->initialize(unit);
138 void sc_synth::set(slot_index_t slot_index, sample val)
140 if (slot_index >= mNumControls) {
141 log("argument number out of range\n");
142 return;
145 mControlRates[slot_index] = 0;
146 mMapControls[slot_index] = &mControls[slot_index];
147 mControls[slot_index] = val;
150 void sc_synth::set_control_array(slot_index_t slot_index, size_t count, sample * val)
152 if (slot_index+count >= mNumControls)
153 return;
154 for (size_t i = 0; i != count; ++i)
155 set(slot_index+i, val[i]);
159 void sc_synth::map_control_bus_control (unsigned int slot_index, int control_bus_index)
161 if (slot_index >= mNumControls)
162 return;
164 World *world = mNode.mWorld;
165 if (control_bus_index < 0) {
166 mControlRates[slot_index] = 0;
167 mMapControls[slot_index] = mControls + slot_index;
169 else if (uint32(control_bus_index) < world->mNumControlBusChannels) {
170 mControlRates[slot_index] = 1;
171 mMapControls[slot_index] = world->mControlBus + control_bus_index;
175 void sc_synth::map_control_buses_control (unsigned int slot_index, int control_bus_index, int count)
177 if (slot_index >= mNumControls)
178 return;
180 int slots_to_set = std::min(count, int(mNumControls - slot_index));
182 for (int i = 0; i != slots_to_set; ++i)
183 map_control_bus_control(slot_index+i, control_bus_index+i);
186 void sc_synth::map_control_bus_audio (unsigned int slot_index, int audio_bus_index)
188 if (slot_index >= mNumControls)
189 return;
191 World *world = mNode.mWorld;
193 if (audio_bus_index < 0) {
194 mControlRates[slot_index] = 0;
195 mMapControls[slot_index] = mControls + slot_index;
196 } else if (uint(audio_bus_index) < world->mNumAudioBusChannels) {
197 mControlRates[slot_index] = 2;
198 mMapControls[slot_index] = world->mAudioBus + (audio_bus_index * world->mBufLength);
202 void sc_synth::map_control_buses_audio (unsigned int slot_index, int audio_bus_index, int count)
204 if (slot_index >= mNumControls)
205 return;
207 int slots_to_set = std::min(count, int(mNumControls - slot_index));
209 for (int i = 0; i != slots_to_set; ++i)
210 map_control_bus_audio(slot_index+i, audio_bus_index+i);
213 void sc_synth::apply_unit_cmd(const char * unit_cmd, unsigned int unit_index, struct sc_msg_iter *args)
215 Unit * unit = units[unit_index];
216 sc_ugen_def * def = reinterpret_cast<sc_ugen_def*>(unit->mUnitDef);
218 def->run_unit_command(unit_cmd, unit, args);
221 void sc_synth::run(void)
223 perform();
226 extern spin_lock log_guard;
228 #if defined(__GNUC__) && !defined(__APPLE__)
229 #define thread_local __thread
230 #endif
232 #ifdef thread_local
233 static thread_local boost::array<char, 32768> trace_scratchpad;
234 #else
235 static boost::array<char, 32768> trace_scratchpad;
236 #endif
238 struct scratchpad_printer
240 scratchpad_printer(char * str):
241 string(str), position(0)
243 clear();
246 void printf(const char *fmt, ...)
248 va_list vargs;
249 va_start(vargs, fmt);
250 printf(fmt, vargs);
253 const char * data(void) const
255 return string;
258 bool shouldFlush(void) const
260 return position + 1024 > 32768;
263 void clear(void)
265 position = 0;
266 string[0] = '\0'; // zero-terminated
269 private:
270 void printf(const char *fmt, va_list vargs)
272 position += vsprintf(string + position, fmt, vargs);
275 char * string;
276 int position;
279 void sc_synth::run_traced(void)
281 trace = 0;
283 #ifndef thread_local
284 spin_lock::scoped_lock lock (log_guard);
285 #endif
287 scratchpad_printer printer(trace_scratchpad.data());
289 printer.printf("\nTRACE %d %s #units: %d\n", id(), this->prototype_name(), calc_unit_count);
291 for (size_t i = 0; i != calc_unit_count; ++i) {
292 Unit * unit = calc_units[i];
294 sc_ugen_def * def = reinterpret_cast<sc_ugen_def*>(unit->mUnitDef);
295 printer.printf(" unit %zd %s\n in ", i, def->name());
296 for (uint16_t j=0; j!=unit->mNumInputs; ++j) {
297 printer.printf(" %g", unit->mInBuf[j][0]);
298 if (printer.shouldFlush()) {
299 #ifdef thread_local
300 spin_lock::scoped_lock lock (log_guard);
301 #endif
302 log(printer.data());
303 printer.clear();
307 printer.printf("\n");
309 (unit->mCalcFunc)(unit, unit->mBufLength);
311 printer.printf(" out");
312 for (int j=0; j<unit->mNumOutputs; ++j) {
313 printer.printf(" %g", unit->mOutBuf[j][0]);
314 if (printer.shouldFlush()) {
315 #ifdef thread_local
316 spin_lock::scoped_lock lock (log_guard);
317 #endif
318 log(printer.data());
319 printer.clear();
322 printer.printf("\n");
324 printer.printf("\n");
326 #ifdef thread_local
327 spin_lock::scoped_lock lock (log_guard);
328 #endif
329 log(printer.data());
332 } /* namespace nova */