Arp.cpp (11920B)
1 2 #include "Arp.hpp" 3 #include <unordered_set> 4 5 #define NOTES_IMMEDIATE_MODE "notes_immediate" 6 #define FIXED_GATE_MODE "fixed_gate" 7 8 void Arp::NoteSet::Note::reset() { 9 pitch = 0.0f; 10 channel = -1; 11 } 12 13 bool Arp::NoteSet::nextPitch(Mode mode, float& pitchOut) { 14 if (_syncNext) { 15 _syncNext = false; 16 sync(); 17 } 18 if (_noteCount <= 0) { 19 return false; 20 } 21 22 switch (mode) { 23 case UP_MODE: { 24 _playIndex = (_playIndex + 1) % _noteCount; 25 _syncNext = _syncTo && _playIndex == _noteCount - 1; 26 pitchOut = _notesByPitch[_playIndex].pitch; 27 return true; 28 } 29 30 case DOWN_MODE: { 31 --_playIndex; 32 if (_playIndex < 0) { 33 _playIndex = _noteCount - 1; 34 } 35 _syncNext = _syncTo && _playIndex == 0; 36 pitchOut = _notesByPitch[_playIndex].pitch; 37 return true; 38 } 39 40 case UP_DOWN_MODE: { 41 if (_up) { 42 ++_playIndex; 43 if (_playIndex >= _noteCount) { 44 _playIndex = std::max(0, _noteCount - 2); 45 _up = false; 46 } 47 } 48 else { 49 --_playIndex; 50 if (_playIndex < 0) { 51 _playIndex = 1 % _noteCount; 52 _up = true; 53 } 54 _syncNext = _syncTo && (_playIndex == 0 || _playIndex == 1); 55 } 56 pitchOut = _notesByPitch[_playIndex].pitch; 57 return true; 58 } 59 60 case UP_DOWN_REPEAT_MODE: { 61 if (_up) { 62 ++_playIndex; 63 if (_playIndex >= _noteCount) { 64 _playIndex = _noteCount - 1; 65 _up = false; 66 } 67 } 68 else { 69 --_playIndex; 70 if (_playIndex < 0) { 71 _playIndex = 0; 72 _up = true; 73 } 74 _syncNext = _syncTo && _playIndex == 0; 75 } 76 pitchOut = _notesByPitch[_playIndex].pitch; 77 return true; 78 } 79 80 case IN_ORDER_MODE: { 81 _playIndex = (_playIndex + 1) % _noteCount; 82 _syncNext = _syncTo && _playIndex == _noteCount - 1; 83 pitchOut = _notesAsPlayed[_playIndex].pitch; 84 return true; 85 } 86 87 case RANDOM_MODE: { 88 _playIndex = (_playIndex + 1) % _noteCount; 89 _syncNext = _syncTo && _playIndex == _noteCount - 1; 90 pitchOut = _notesAsPlayed[random::u32() % _noteCount].pitch; 91 return true; 92 } 93 94 case SHUFFLE_MODE: { 95 _playIndex = (_playIndex + 1) % _noteCount; 96 if (_playIndex == 0) { 97 std::fill(_shuffleMask, _shuffleMask + maxChannels, false); 98 } 99 _syncNext = _syncTo && _playIndex == _noteCount - 1; 100 101 int n = random::u32() % (_noteCount - _playIndex); 102 int i = 0; 103 for (; i < _noteCount; ++i) { 104 if (!_shuffleMask[i]) { 105 if (n < 1) { 106 _shuffleMask[i] = true; 107 break; 108 } 109 --n; 110 } 111 } 112 pitchOut = _notesAsPlayed[i].pitch; 113 return true; 114 } 115 } 116 117 assert(false); 118 return false; 119 } 120 121 void Arp::NoteSet::reset() { 122 resetSequence(); 123 _notesDirty = false; 124 _noteCount = 0; 125 for (int c = 0; c < maxChannels; ++c) { 126 _noteOn[c] = false; 127 _notesAsPlayed[c].reset(); 128 _notesByPitch[c].reset(); 129 } 130 } 131 132 void Arp::NoteSet::resetSequence() { 133 _playIndex = -1; 134 _up = true; 135 } 136 137 void Arp::NoteSet::addNote(int c, float pitch) { 138 for (int i = 0; i < _noteCount; ++i) { 139 if (_notesByPitch[i].pitch == pitch) { 140 return; 141 } 142 } 143 144 dropNote(c); 145 _noteOn[c] = true; 146 _notesDirty = true; 147 148 Note n; 149 n.pitch = pitch; 150 n.channel = c; 151 int i = 0; 152 while (n.pitch >= _notesByPitch[i].pitch && i < _noteCount) { 153 ++i; 154 } 155 assert(i <= maxChannels); 156 157 if (i >= maxChannels) { 158 i = maxChannels - 1; 159 } 160 else { 161 shuffleUp(_notesByPitch, i); 162 } 163 _notesByPitch[i] = n; 164 165 _notesAsPlayed[_noteCount] = n; 166 ++_noteCount; 167 assert(_noteCount <= maxChannels); 168 assert(uniqueChannelsCount(_notesAsPlayed) == _noteCount); 169 assert(uniqueChannelsCount(_notesByPitch) == _noteCount); 170 } 171 172 void Arp::NoteSet::dropNote(int c) { 173 if (!_noteOn[c]) { 174 return; 175 } 176 _noteOn[c] = false; 177 _notesDirty = true; 178 179 assert(_noteCount > 0); 180 int i = 0; 181 while (_notesAsPlayed[i].channel != c && i < _noteCount) { 182 ++i; 183 } 184 assert(i < _noteCount); 185 shuffleDown(_notesAsPlayed, i); 186 _notesAsPlayed[_noteCount - 1].reset(); 187 188 i = 0; 189 while (_notesByPitch[i].channel != c && i < _noteCount) { 190 ++i; 191 } 192 assert(i < _noteCount); 193 shuffleDown(_notesByPitch, i); 194 _notesByPitch[_noteCount - 1].reset(); 195 196 --_noteCount; 197 assert(_noteCount >= 0); 198 assert(uniqueChannelsCount(_notesAsPlayed) == _noteCount); 199 assert(uniqueChannelsCount(_notesByPitch) == _noteCount); 200 } 201 202 void Arp::NoteSet::shuffleUp(Note* notes, int index) { 203 for (int i = _noteCount; i > index; --i) { 204 notes[i] = notes[i - 1]; 205 } 206 } 207 208 void Arp::NoteSet::shuffleDown(Note* notes, int index) { 209 for (int n = _noteCount - 1; index < n; ++index) { 210 notes[index] = notes[index + 1]; 211 } 212 } 213 214 void Arp::NoteSet::sync() { 215 if (!_syncTo || !_syncTo->_notesDirty) { 216 return; 217 } 218 219 _noteCount = _syncTo->_noteCount; 220 _playIndex = -1; 221 std::copy(_syncTo->_noteOn, _syncTo->_noteOn + maxChannels, _noteOn); 222 std::copy(_syncTo->_notesAsPlayed, _syncTo->_notesAsPlayed + _noteCount, _notesAsPlayed); 223 std::copy(_syncTo->_notesByPitch, _syncTo->_notesByPitch + _noteCount, _notesByPitch); 224 _syncTo->_notesDirty = false; 225 } 226 227 int Arp::NoteSet::uniqueChannelsCount(Note* notes) { 228 std::unordered_set<int> channels; 229 for (int i = 0; i < maxChannels; ++i) { 230 if (notes[i].channel >= 0) { 231 channels.insert(notes[i].channel); 232 } 233 } 234 return channels.size(); 235 } 236 237 void Arp::reset() { 238 _clockTrigger.reset(); 239 _resetTrigger.reset(); 240 _anyHigh = false; 241 _secondsSinceLastClock = -1.0f; 242 _clockSeconds = 0.1f; 243 _gateGenerator.process(1000.0f); 244 for (int c = 0; c < maxChannels; ++c) { 245 _gateTrigger[c].reset(); 246 _gateHigh[c] = false; 247 } 248 _currentNotes->reset(); 249 _playbackNotes->reset(); 250 } 251 252 void Arp::sampleRateChange() { 253 _sampleTime = APP->engine->getSampleTime(); 254 } 255 256 json_t* Arp::saveToJson(json_t* root) { 257 json_object_set_new(root, NOTES_IMMEDIATE_MODE, json_boolean(_notesImmediate)); 258 json_object_set_new(root, FIXED_GATE_MODE, json_boolean(_fixedGate)); 259 return root; 260 } 261 262 void Arp::loadFromJson(json_t* root) { 263 json_t* ni = json_object_get(root, NOTES_IMMEDIATE_MODE); 264 if (ni) { 265 _notesImmediate = json_is_true(ni); 266 } 267 268 json_t* fg = json_object_get(root, FIXED_GATE_MODE); 269 if (fg) { 270 _fixedGate = json_is_true(fg); 271 } 272 } 273 274 int Arp::channels() { 275 return inputs[PITCH_INPUT].getChannels(); 276 } 277 278 void Arp::addChannel(int c) { 279 _gateTrigger[c].reset(); 280 } 281 282 void Arp::removeChannel(int c) { 283 _currentNotes->dropNote(c); 284 } 285 286 void Arp::modulate() { 287 _mode = (Mode)clamp(params[MODE_PARAM].getValue(), 0.0f, 6.0f); 288 _gateLength = clamp(params[GATE_LENGTH_PARAM].getValue(), 0.0f, 1.0f); 289 290 bool hold = params[HOLD_PARAM].getValue() > 0.5f; 291 if (_hold && !hold) { 292 dropAllNotes(); 293 } 294 _hold = hold; 295 } 296 297 void Arp::processAll(const ProcessArgs& args) { 298 lights[UP_LIGHT].value = _mode == UP_MODE; 299 lights[DOWN_LIGHT].value = _mode == DOWN_MODE; 300 lights[UP_DOWN_LIGHT].value = _mode == UP_DOWN_MODE; 301 lights[UP_DOWN_REPEAT_LIGHT].value = _mode == UP_DOWN_REPEAT_MODE; 302 lights[IN_ORDER_LIGHT].value = _mode == IN_ORDER_MODE; 303 lights[RANDOM_LIGHT].value = _mode == RANDOM_MODE; 304 lights[SHUFFLE_LIGHT].value = _mode == SHUFFLE_MODE; 305 306 if (_resetTrigger.process(inputs[RESET_INPUT].getVoltage())) { 307 _currentNotes->resetSequence(); 308 _playbackNotes->resetSequence(); 309 } 310 311 bool wasAnyHigh = _anyHigh; 312 _anyHigh = false; 313 bool firstAdd = true; 314 for (int c = 0; c < _channels; ++c) { 315 if (_gateTrigger[c].process(inputs[GATE_INPUT].getPolyVoltage(c))) { 316 if (_hold && !wasAnyHigh && firstAdd) { 317 dropAllNotes(); 318 } 319 firstAdd = false; 320 _anyHigh = true; 321 _gateHigh[c] = true; 322 _currentNotes->addNote(c, inputs[PITCH_INPUT].getPolyVoltage(c)); 323 if (_currentNotes->noteCount() == 1) { 324 _playbackNotes->sync(); 325 } 326 } 327 else if (_gateHigh[c]) { 328 if (!_gateTrigger[c].isHigh()) { 329 _gateHigh[c] = false; 330 if (!_hold) { 331 _currentNotes->dropNote(c); 332 } 333 } 334 else { 335 _anyHigh = true; 336 } 337 } 338 } 339 340 bool clock = false; 341 if (inputs[CLOCK_INPUT].isConnected()) { 342 clock = _clockTrigger.process(inputs[CLOCK_INPUT].getVoltage()); 343 if (clock) { 344 if (_secondsSinceLastClock > 0.0f) { 345 _clockSeconds = _secondsSinceLastClock; 346 } 347 _secondsSinceLastClock = 0.0f; 348 } 349 _secondsSinceLastClock += _sampleTime; 350 } 351 352 NoteSet* notes = _notesImmediate ? _currentNotes : _playbackNotes; 353 if (clock) { 354 if (notes->nextPitch(_mode, _pitchOut)) { 355 _gateGenerator.reset(); 356 float gl = _gateLength; 357 if (_fixedGate) { 358 gl *= 0.5f; 359 } 360 else { 361 gl *= _clockSeconds; 362 } 363 _gateGenerator.trigger(std::max(0.001f, gl)); 364 } 365 } 366 outputs[PITCH_OUTPUT].setVoltage(_pitchOut); 367 outputs[GATE_OUTPUT].setVoltage(_gateGenerator.process(_sampleTime) * 5.0f); 368 } 369 370 void Arp::dropAllNotes() { 371 for (int c = 0; c < _channels; ++c) { 372 if (!_gateHigh[c]) { 373 _currentNotes->dropNote(c); 374 } 375 } 376 } 377 378 struct ArpWidget : BGModuleWidget { 379 static constexpr int hp = 3; 380 381 ArpWidget(Arp* module) { 382 setModule(module); 383 box.size = Vec(RACK_GRID_WIDTH * hp, RACK_GRID_HEIGHT); 384 setPanel(box.size, "Arp"); 385 createScrews(); 386 387 // generated by svg_widgets.rb 388 auto modeParamPosition = Vec(24.0, 57.0); 389 auto gateLengthParamPosition = Vec(14.5, 87.5); 390 auto holdParamPosition = Vec(29.0, 114.0); 391 392 auto clockInputPosition = Vec(10.5, 132.0); 393 auto resetInputPosition = Vec(10.5, 167.0); 394 auto pitchInputPosition = Vec(10.5, 202.0); 395 auto gateInputPosition = Vec(10.5, 237.0); 396 397 auto pitchOutputPosition = Vec(10.5, 275.0); 398 auto gateOutputPosition = Vec(10.5, 310.0); 399 400 auto upLightPosition = Vec(3.0, 28.0); 401 auto downLightPosition = Vec(24.0, 28.0); 402 auto upDownLightPosition = Vec(3.0, 38.0); 403 auto upDownRepeatLightPosition = Vec(24.0, 38.0); 404 auto inOrderLightPosition = Vec(3.0, 48.0); 405 auto randomLightPosition = Vec(24.0, 48.0); 406 auto shuffleLightPosition = Vec(3.0, 58.0); 407 // end generated by svg_widgets.rb 408 409 addParam(createParam<StatefulButton9>(modeParamPosition, module, Arp::MODE_PARAM)); 410 addParam(createParam<Knob16>(gateLengthParamPosition, module, Arp::GATE_LENGTH_PARAM)); 411 addParam(createParam<IndicatorButtonGreen9>(holdParamPosition, module, Arp::HOLD_PARAM)); 412 413 addInput(createInput<Port24>(clockInputPosition, module, Arp::CLOCK_INPUT)); 414 addInput(createInput<Port24>(resetInputPosition, module, Arp::RESET_INPUT)); 415 addInput(createInput<Port24>(pitchInputPosition, module, Arp::PITCH_INPUT)); 416 addInput(createInput<Port24>(gateInputPosition, module, Arp::GATE_INPUT)); 417 418 addOutput(createOutput<Port24>(pitchOutputPosition, module, Arp::PITCH_OUTPUT)); 419 addOutput(createOutput<Port24>(gateOutputPosition, module, Arp::GATE_OUTPUT)); 420 421 addChild(createLight<BGSmallLight<GreenLight>>(upLightPosition, module, Arp::UP_LIGHT)); 422 addChild(createLight<BGSmallLight<GreenLight>>(downLightPosition, module, Arp::DOWN_LIGHT)); 423 addChild(createLight<BGSmallLight<GreenLight>>(upDownLightPosition, module, Arp::UP_DOWN_LIGHT)); 424 addChild(createLight<BGSmallLight<GreenLight>>(upDownRepeatLightPosition, module, Arp::UP_DOWN_REPEAT_LIGHT)); 425 addChild(createLight<BGSmallLight<GreenLight>>(inOrderLightPosition, module, Arp::IN_ORDER_LIGHT)); 426 addChild(createLight<BGSmallLight<GreenLight>>(randomLightPosition, module, Arp::RANDOM_LIGHT)); 427 addChild(createLight<BGSmallLight<GreenLight>>(shuffleLightPosition, module, Arp::SHUFFLE_LIGHT)); 428 } 429 430 void contextMenu(Menu* menu) override { 431 auto m = dynamic_cast<Arp*>(module); 432 assert(m); 433 434 OptionsMenuItem* ni = new OptionsMenuItem("Use new notes"); 435 ni->addItem(OptionMenuItem("On arpeggio restart", [m]() { return !m->_notesImmediate; }, [m]() { m->_notesImmediate = false; })); 436 ni->addItem(OptionMenuItem("Immediately", [m]() { return m->_notesImmediate; }, [m]() { m->_notesImmediate = true; })); 437 OptionsMenuItem::addToMenu(ni, menu); 438 439 OptionsMenuItem* fg = new OptionsMenuItem("Max gate length"); 440 fg->addItem(OptionMenuItem("Clock interval", [m]() { return !m->_fixedGate; }, [m]() { m->_fixedGate = false; })); 441 fg->addItem(OptionMenuItem("Fixed (500ms)", [m]() { return m->_fixedGate; }, [m]() { m->_fixedGate = true; })); 442 OptionsMenuItem::addToMenu(fg, menu); 443 } 444 }; 445 446 Model* modelArp = createModel<Arp, ArpWidget>("Bogaudio-Arp", "ARP", "Polyphonic-input arpeggiator", "Arpeggiator", "Polyphonic");