1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html 2 3 #ifndef SPECTMORPH_PROJECT_HH 4 #define SPECTMORPH_PROJECT_HH 5 6 #include "sminstrument.hh" 7 #include "smwavset.hh" 8 #include "smwavsetbuilder.hh" 9 #include "smobject.hh" 10 #include "smbuilderthread.hh" 11 #include "smmorphplan.hh" 12 #include "smuserinstrumentindex.hh" 13 14 #include <thread> 15 #include <mutex> 16 17 namespace SpectMorph 18 { 19 20 class MidiSynth; 21 class SynthInterface; 22 class MorphWavSource; 23 24 class SynthControlEvent 25 { 26 public: 27 virtual void run_rt (Project *project) = 0; 28 virtual ~SynthControlEvent()29 ~SynthControlEvent() 30 { 31 } 32 }; 33 34 struct InstFunc : public SynthControlEvent 35 { 36 std::function<void(Project *)> func; 37 std::function<void()> free_func; 38 public: InstFuncSpectMorph::InstFunc39 InstFunc (const std::function<void(Project *)>& func, 40 const std::function<void()>& free_func) : 41 func (func), 42 free_func (free_func) 43 { 44 } ~InstFuncSpectMorph::InstFunc45 ~InstFunc() 46 { 47 free_func(); 48 } 49 void run_rtSpectMorph::InstFunc50 run_rt (Project *project) 51 { 52 func (project); 53 } 54 }; 55 56 class ControlEventVector 57 { 58 std::vector<std::unique_ptr<SynthControlEvent>> events; 59 bool clear = false; 60 public: 61 void take (SynthControlEvent *ev); 62 void run_rt (Project *project); 63 }; 64 65 class Project : public SignalReceiver 66 { 67 public: 68 enum class StorageModel { 69 COPY, 70 REFERENCE 71 }; 72 73 private: 74 std::vector<std::shared_ptr<WavSet>> wav_sets; 75 76 std::unique_ptr<MidiSynth> m_midi_synth; 77 double m_mix_freq = 0; 78 double m_volume = -6; 79 RefPtr<MorphPlan> m_morph_plan; 80 std::vector<unsigned char> m_last_plan_data; 81 bool m_state_changed_notify = false; 82 StorageModel m_storage_model = StorageModel::COPY; 83 84 std::mutex m_synth_mutex; 85 ControlEventVector m_control_events; // protected by synth mutex 86 std::vector<std::string> m_out_events; // protected by synth mutex 87 bool m_voices_active = false; // protected by synth mutex 88 bool m_state_changed = false; // protected by synth mutex 89 90 std::unique_ptr<SynthInterface> m_synth_interface; 91 92 UserInstrumentIndex m_user_instrument_index; 93 BuilderThread m_builder_thread; 94 95 std::map<int, std::unique_ptr<Instrument>> instrument_map; 96 97 std::vector<MorphWavSource *> list_wav_sources(); 98 99 Error load_internal (ZipReader& zip_reader, MorphPlan::ExtraParameters *params); 100 void post_load(); 101 102 void on_plan_changed(); 103 void on_operator_added (MorphOperator *op); 104 void on_operator_removed (MorphOperator *op); 105 106 public: 107 Project(); 108 109 Instrument *get_instrument (MorphWavSource *wav_source); 110 111 void rebuild (MorphWavSource *wav_source); 112 void add_rebuild_result (int object_id, WavSet *wav_set); 113 void clear_wav_sets(); 114 bool rebuild_active (int object_id); 115 116 std::shared_ptr<WavSet> get_wav_set (int object_id); 117 118 void synth_take_control_event (SynthControlEvent *event); 119 120 std::mutex& synth_mutex()121 synth_mutex() 122 { 123 /* the synthesis thread will typically not block on synth_mutex 124 * instead, it tries locking it, and if that fails, continues 125 * 126 * the ui thread will block on the synth_mutex to enqueue events, 127 * parameter changes (in form of a new morph plan, volume, ...) 128 * and so on 129 * 130 * if the synthesis thread can obtain a lock, it will then be 131 * able to process these events to update its internal state 132 * and also send notifications back to the ui 133 */ 134 return m_synth_mutex; 135 } 136 bool try_update_synth(); 137 void set_mix_freq (double mix_freq); 138 void set_storage_model (StorageModel model); 139 void set_state_changed_notify (bool notify); 140 void state_changed(); 141 bool voices_active(); 142 143 void set_volume (double new_volume); 144 double volume() const; 145 146 std::vector<std::string> notify_take_events(); 147 SynthInterface *synth_interface() const; 148 MidiSynth *midi_synth() const; 149 MorphPlanPtr morph_plan() const; 150 UserInstrumentIndex *user_instrument_index(); 151 152 Error save (const std::string& filename); 153 Error save (ZipWriter& zip_writer, MorphPlan::ExtraParameters *params); 154 Error load (const std::string& filename); 155 Error load (ZipReader& zip_reader, MorphPlan::ExtraParameters *params); 156 Error load_compat (GenericIn *in, MorphPlan::ExtraParameters *params); 157 158 std::string save_plan_lv2 (std::function<std::string(std::string)> abstract_path); 159 void load_plan_lv2 (std::function<std::string(std::string)> absolute_path, const std::string& plan); 160 void clear_lv2_filenames(); 161 162 Signal<double> signal_volume_changed; 163 }; 164 165 } 166 167 #endif 168