Пример #1
0
  void SimpleDelay::process() {
    MOPO_ASSERT(inputMatchesBufferSize(kAudio));
    MOPO_ASSERT(inputMatchesBufferSize(kFeedback));
    MOPO_ASSERT(inputMatchesBufferSize(kSampleDelay));

    mopo_float* dest = output()->buffer;
    const mopo_float* audio = input(kAudio)->source->buffer;
    const mopo_float* feedback = input(kFeedback)->source->buffer;
    if (feedback[0] == 0.0 && feedback[buffer_size_ - 1] == 0.0) {
      memcpy(dest, audio, sizeof(mopo_float) * buffer_size_);
      memory_->pushBlock(audio, buffer_size_);
      return;
    }

    const mopo_float* period = input(kSampleDelay)->source->buffer;

    int i = 0;
    if (input(kReset)->source->triggered) {
      int trigger_offset = input(kReset)->source->trigger_offset;

      for (; i < trigger_offset; ++i)
        tick(i, dest, audio, period, feedback);

      int clear_samples = std::min(MAX_CLEAR_SAMPLES, ((int)period[i]) + 1);
      memory_->pushZero(clear_samples);
    }

    for (int i = 0; i < buffer_size_; ++i)
      tick(i, dest, audio, period, feedback);
  }
Пример #2
0
  void StateVariableFilter::computePassCoefficients(mopo_float blend,
                                                    mopo_float cutoff,
                                                    mopo_float resonance,
                                                    bool db24) {
    MOPO_ASSERT(resonance > 0.0);
    MOPO_ASSERT(cutoff > 0.0);

    if (db24)
      resonance = sqrt(resonance);

    mopo_float g = tan(PI * utils::min(cutoff / sample_rate_, 0.5));
    mopo_float k = 1.0 / resonance;

    mopo_float low_pass_amount = sqrt(utils::clamp(1.0 - blend, 0.0, 1.0));
    mopo_float band_pass_amount = sqrt(utils::clamp(1.0 - fabs(blend - 1.0), 0.0, 1.0));
    mopo_float high_pass_amount = sqrt(utils::clamp(blend - 1.0, 0.0, 1.0));

    target_m0_ = 0.0;
    target_m1_ = band_pass_amount;
    target_m2_ = low_pass_amount;

    target_m0_ += high_pass_amount;
    target_m1_ += -k * high_pass_amount;
    target_m2_ += -high_pass_amount;
    
    a1_ = 1.0 / (1.0 + g * (g + k));
    a2_ = g * a1_;
    a3_ = g * a2_;
  }
Пример #3
0
  ValueDetailsLookup::ValueDetailsLookup() {
    int num_parameters = sizeof(parameter_list) / sizeof(ValueDetails);
    for (int i = 0; i < num_parameters; ++i) {
      details_lookup_[parameter_list[i].name] = parameter_list[i];

      MOPO_ASSERT(parameter_list[i].default_value <= parameter_list[i].max);
      MOPO_ASSERT(parameter_list[i].default_value >= parameter_list[i].min);
    }
  }
Пример #4
0
  void Processor::plug(const Output* source, unsigned int input_index) {
    MOPO_ASSERT(input_index < inputs_.size());
    MOPO_ASSERT(source);

    inputs_[input_index]->source = source;

    if (router_)
      router_->connect(this, source, input_index);
  }
Пример #5
0
  void VoiceHandler::noteOn(mopo_float note, mopo_float velocity, int sample, int channel) {
    MOPO_ASSERT(sample >= 0 && sample < buffer_size_);
    MOPO_ASSERT(channel >= 0 && channel < NUM_MIDI_CHANNELS);

    Voice* voice = grabVoice();
    pressed_notes_.push_front(note);

    if (last_played_note_ < 0)
      last_played_note_ = note;
    voice->activate(note, velocity, last_played_note_, pressed_notes_.size(), sample, channel);
    active_voices_.push_back(voice);
    last_played_note_ = note;
  }
Пример #6
0
  void StateVariableFilter::computeShelfCoefficients(Shelves choice,
                                                     mopo_float cutoff,
                                                     mopo_float gain) {
    MOPO_ASSERT(gain >= 0.0);
    MOPO_ASSERT(cutoff > 0.0);

    gain = sqrt(gain);

    mopo_float g = tan(PI * utils::min(cutoff / sample_rate_, 0.5));
    mopo_float k = 1.0;

    switch(choice) {
      case kLowShelf: {
        g /= sqrt(gain);
        target_m0_ = 1.0;
        target_m1_ = k * (gain - 1.0);
        target_m2_ = gain * gain - 1.0;
        break;
      }
      case kBandShelf: {
        k /= gain;
        target_m0_ = 1.0;
        target_m1_ = k * (gain * gain - 1.0);
        target_m2_ = 0.0;
        break;
      }
      case kHighShelf: {
        g *= sqrt(gain);
        target_m0_ = gain * gain;
        target_m1_ = k * gain * (1.0 - gain);
        target_m2_ = 1.0 - gain * gain;
        break;
      }
      default: {
        target_m0_ = 0.0;
        target_m1_ = 0.0;
        target_m2_ = 0.0;
      }
    }

    a1_ = 1.0 / (1.0 + g * (g + k));
    a2_ = g * a1_;
    a3_ = g * a2_;

    if (last_shelf_ != choice) {
      reset();
      last_shelf_ = choice;
    }
  }
Пример #7
0
  void HelmEngine::connectModulation(ModulationConnection* connection) {
    Processor::Output* source = getModulationSource(connection->source);
    MOPO_ASSERT(source != 0);
    
    Processor* destination = getModulationDestination(connection->destination,
                                                      source->owner->isPolyphonic());
    MOPO_ASSERT(destination != 0);

    connection->modulation_scale.plug(source, 0);
    connection->modulation_scale.plug(&connection->amount, 1);
    connection->modulation_scale.setControlRate(source->owner->isControlRate());
    destination->plugNext(&connection->modulation_scale);

    source->owner->router()->addProcessor(&connection->modulation_scale);
    mod_connections_.insert(connection);
  }
Пример #8
0
  void LinearSlope::process() {
    MOPO_ASSERT(inputMatchesBufferSize(kTarget));
    MOPO_ASSERT(inputMatchesBufferSize(kRunSeconds));

    int i = 0;
    if (input(kTriggerJump)->source->triggered) {
      int trigger_offset = input(kTriggerJump)->source->trigger_offset;
      for (; i < trigger_offset; ++i)
        tick(i);

      last_value_ = input(kTarget)->at(i);
    }

    for (; i < buffer_size_; ++i)
      tick(i);
  }
Пример #9
0
  void Oscillator::process() {
    MOPO_ASSERT(inputMatchesBufferSize(kFrequency));
    MOPO_ASSERT(inputMatchesBufferSize(kPhase));

    preprocess();

    int i = 0;
    if (input(kReset)->source->triggered &&
        input(kReset)->source->trigger_value == kVoiceReset) {
      int trigger_offset = input(kReset)->source->trigger_offset;
      for (; i < trigger_offset; ++i)
        tick(i);

      offset_ = 0.0;
    }
    for (; i < buffer_size_; ++i)
      tick(i);
  }
Пример #10
0
void SynthBase::updateMemoryOutput(int samples, const mopo::mopo_float* left,
                                                const mopo::mopo_float* right) {
  mopo::mopo_float last_played = std::max(engine_.getLastActiveNote(), OUTPUT_WINDOW_MIN_NOTE);
  int output_inc = engine_.getSampleRate() / mopo::MEMORY_SAMPLE_RATE;

  if (last_played && last_played_note_ != last_played) {
    last_played_note_ = last_played;
    
    mopo::mopo_float frequency = mopo::utils::midiNoteToFrequency(last_played_note_);
    mopo::mopo_float period = engine_.getSampleRate() / frequency;
    int window_length = output_inc * mopo::MEMORY_RESOLUTION;

    memory_reset_period_ = period;
    while (memory_reset_period_ < window_length)
      memory_reset_period_ += memory_reset_period_;

    memory_reset_period_ = std::min(memory_reset_period_, 2.0 * window_length);
    memory_index_ = 0;
  }

  for (; memory_input_offset_ < samples; memory_input_offset_ += output_inc) {
    int input_index = mopo::utils::iclamp(memory_input_offset_, 0, samples);
    memory_index_ = mopo::utils::iclamp(memory_index_, 0, 2 * mopo::MEMORY_RESOLUTION - 1);
    MOPO_ASSERT(input_index >= 0);
    MOPO_ASSERT(input_index < samples);
    MOPO_ASSERT(memory_index_ >= 0);
    MOPO_ASSERT(memory_index_ < 2 * mopo::MEMORY_RESOLUTION);
    output_memory_write_[memory_index_++] = left[input_index] + right[input_index];

    if (memory_index_ * output_inc >= memory_reset_period_) {
      memory_input_offset_ += memory_reset_period_ - memory_index_ * output_inc;
      memory_index_ = 0;
      memcpy(output_memory_, output_memory_write_, 2 * mopo::MEMORY_RESOLUTION * sizeof(float));
    }
  }

  memory_input_offset_ -= samples;
}
Пример #11
0
  void PortamentoSlope::process() {
    MOPO_ASSERT(inputMatchesBufferSize(kTarget));

    processTriggers();
    int state = static_cast<int>(input(kPortamentoType)->at(0));
    mopo_float run_seconds = input(kRunSeconds)->at(0);
    if (state == kPortamentoOff || utils::closeToZero(run_seconds)) {
      processBypass(0);
      return;
    }

    mopo_float increment = 0.4 / (sample_rate_ * input(kRunSeconds)->at(0));
    mopo_float decay = 0.07 / (sample_rate_ * input(kRunSeconds)->at(0));
    const mopo_float* targets = input(kTarget)->source->buffer;

    int i = 0;
    int note_number = static_cast<int>(input(kNoteNumber)->source->trigger_value);

    if (state == kPortamentoAuto && note_number <= 1 && input(kTriggerJump)->source->triggered) {
      int trigger_offset = input(kTriggerJump)->source->trigger_offset;
      for (; i < trigger_offset; ++i)
        tick(i, targets[i], increment, decay);

      last_value_ = input(kTarget)->at(trigger_offset);
    }
    else if (input(kTriggerStart)->source->triggered) {
      int trigger_offset = input(kTriggerStart)->source->trigger_offset;
      for (; i < trigger_offset; ++i)
        tick(i, targets[i], increment, decay);

      last_value_ = input(kTriggerStart)->source->trigger_value;
    }

    if (last_value_ == input(kTarget)->at(0) &&
        last_value_ == input(kTarget)->at(buffer_size_ - 1)) {
      processBypass(i);
    }
    else {
      for (; i < buffer_size_; ++i)
        tick(i, targets[i], increment, decay);
    }
  }
Пример #12
0
void SynthBase::processAudio(AudioSampleBuffer* buffer, int channels, int samples, int offset) {
  if (engine_.getBufferSize() != samples)
    engine_.setBufferSize(samples);

  engine_.process();

  const mopo::mopo_float* engine_output_left = engine_.output(0)->buffer;
  const mopo::mopo_float* engine_output_right = engine_.output(1)->buffer;
  for (int channel = 0; channel < channels; ++channel) {
    float* channelData = buffer->getWritePointer(channel, offset);
    const mopo::mopo_float* synth_output = (channel % 2) ? engine_output_right : engine_output_left;

    #pragma clang loop vectorize(enable) interleave(enable)
    for (int i = 0; i < samples; ++i) {
      channelData[i] = synth_output[i];
      MOPO_ASSERT(std::isfinite(synth_output[i]));
    }
  }

  updateMemoryOutput(samples, engine_output_left, engine_output_right);
}
Пример #13
0
  void Cursynth::saveConfiguration() {
    confirmPathExists(getConfigPath());

    // Store all the MIDI learn data into JSON.
    cJSON* root = cJSON_CreateObject();
    std::map<int, std::string>::iterator iter = midi_learn_.begin();
    for (; iter != midi_learn_.end(); ++iter) {
      cJSON* midi = cJSON_CreateNumber(iter->first);
      cJSON_AddItemToObject(root, iter->second.c_str(), midi);
    }

    // Write the configuration JSON to the configuration file.
    char* json = cJSON_Print(root);
    std::ofstream save_file;
    save_file.open(getConfigFile().c_str());
    MOPO_ASSERT(save_file.is_open());
    save_file << json;
    save_file.close();

    free(json);
    cJSON_Delete(root);
  }
Пример #14
0
  void StateVariableFilter::process() {
    MOPO_ASSERT(inputMatchesBufferSize(kAudio));

    const mopo_float* audio_buffer = input(kAudio)->source->buffer;
    mopo_float* dest = output()->buffer;

    if (input(kOn)->at(0) == 0.0) {
      processAllPass(audio_buffer, dest);
      return;
    }

    Styles style = static_cast<Styles>(static_cast<int>(input(kStyle)->at(0)));
    bool db24 = style == k24dB;

    mopo_float cutoff = utils::clamp(input(kCutoff)->at(0), MIN_CUTTOFF, sample_rate_);
    mopo_float resonance = utils::clamp(input(kResonance)->at(0),
                                        MIN_RESONANCE, MAX_RESONANCE);
    target_drive_ = input(kDrive)->at(0);

    if (style == kShelf) {
      Shelves shelf_choice = static_cast<Shelves>(static_cast<int>(input(kShelfChoice)->at(0)));
      computeShelfCoefficients(shelf_choice, cutoff, input(kGain)->at(0));
    }
    else {
      mopo_float blend = input(kPassBlend)->at(0);
      computePassCoefficients(blend, cutoff, resonance, db24);
    }

    if (style != last_style_) {
      reset();
      last_style_ = style;
    }

    if (db24)
      process24db(audio_buffer, dest);
    else
      process12db(audio_buffer, dest);
  }
Пример #15
0
  Voice* VoiceHandler::grabVoice() {
    Voice* voice = 0;

    // First check free voices.
    if (free_voices_.size() &&
       (!legato_ || pressed_notes_.size() == 0 || active_voices_.size() < polyphony_)) {
      voice = free_voices_.front();
      free_voices_.pop_front();
      return voice;
    }

    // Next check released voices.
    std::list<Voice*>::iterator iter = active_voices_.begin();
    for (; iter != active_voices_.end(); ++iter) {
      voice = *iter;
      if (voice->key_state() == Voice::kReleased) {
        active_voices_.erase(iter);
        return voice;
      }
    }

    // Then check sustained voices.
    iter = active_voices_.begin();
    for (; iter != active_voices_.end(); ++iter) {
      voice = *iter;
      if (voice->key_state() == Voice::kSustained) {
        active_voices_.erase(iter);
        return voice;
      }
    }

    // If all are active just grab the oldest voice.
    MOPO_ASSERT(active_voices_.size());
    voice = active_voices_.front();
    active_voices_.pop_front();
    return voice;
  }
Пример #16
0
void HelmStandaloneEditor::getNextAudioBlock(const AudioSourceChannelInfo& buffer) {
  ScopedLock lock(critical_section_);
  int num_samples = buffer.buffer->getNumSamples();
  int synth_samples = std::min(num_samples, mopo::MAX_BUFFER_SIZE);

  MOPO_ASSERT(num_samples % synth_samples == 0);

  for (int b = 0; b < num_samples; b += synth_samples) {
    synth_.process();

    const mopo::mopo_float* synth_output_left = synth_.output(0)->buffer;
    const mopo::mopo_float* synth_output_right = synth_.output(1)->buffer;
    for (int channel = 0; channel < mopo::NUM_CHANNELS; ++channel) {
      float* channelData = buffer.buffer->getWritePointer(channel);
      const mopo::mopo_float* synth_output = (channel % 2) ? synth_output_right : synth_output_left;

      for (int i = 0; i < synth_samples; ++i)
        channelData[b + i] = synth_output[i];
    }

    for (int i = 0; i < synth_samples; ++i)
      output_memory_->push(synth_output_left[i] + synth_output_right[i]);
  }
}
Пример #17
0
  Processor::Output* Processor::output(unsigned int index) const {
    MOPO_ASSERT(index < outputs_.size());

    return outputs_[index];
  }
Пример #18
0
  Processor::Input* Processor::input(unsigned int index) const {
    MOPO_ASSERT(index < inputs_.size());

    return inputs_[index];
  }
Пример #19
0
 Arpeggiator::Arpeggiator(NoteHandler* note_handler) :
     Processor(kNumInputs, 1), note_handler_(note_handler),
     sustain_(false), phase_(1.0), note_index_(-1),
     current_octave_(0), octave_up_(true), last_played_note_(0) {
   MOPO_ASSERT(note_handler);
 }
Пример #20
0
 Processor::Output* VoiceHandler::registerOutput(Output* output, int index) {
   MOPO_ASSERT(false);
   return output;
 }