32class Repeat final :
public Selection,
public FormattedTitle {
34 Repeat(l10n::String name, l10n::String title_format_str, uint8_t source_id)
35 :
Selection(name), FormattedTitle(title_format_str), source_id_{source_id} {}
37 [[nodiscard]] std::string_view
getTitle()
const override {
return FormattedTitle::title(); }
40 return isSampleModeSample(modControllable, source_id_);
45 const auto& source = soundEditor.currentSound->sources[source_id_];
46 setValue(source.repeatMode);
48 void writeCurrentValue()
override {
49 const auto current_value = getValue<SampleRepeatMode>();
51 Kit* kit = getCurrentKit();
54 if (kit !=
nullptr && currentUIMode == UI_MODE_HOLDING_AFFECT_ENTIRE_IN_SOUND_EDITOR) {
56 for (
Drum* thisDrum = kit->firstDrum; thisDrum !=
nullptr; thisDrum = thisDrum->next) {
57 if (thisDrum->type == DrumType::SOUND) {
58 auto* soundDrum =
static_cast<SoundDrum*
>(thisDrum);
59 Source* source = &soundDrum->sources[source_id_];
62 if (current_value == SampleRepeatMode::STRETCH) {
63 soundDrum->killAllVoices();
64 source->sampleControls.pitchAndSpeedAreIndependent =
true;
66 else if (source->repeatMode == SampleRepeatMode::STRETCH) {
67 soundDrum->killAllVoices();
68 source->sampleControls.pitchAndSpeedAreIndependent =
false;
71 if (current_value == SampleRepeatMode::ONCE) {
73 sendNoteOffForKitArpeggiator(kit);
76 source->repeatMode = current_value;
82 Source& source = soundEditor.currentSound->sources[source_id_];
85 if (current_value == SampleRepeatMode::STRETCH) {
87 source.sampleControls.pitchAndSpeedAreIndependent =
true;
89 else if (source.repeatMode == SampleRepeatMode::STRETCH) {
91 source.sampleControls.pitchAndSpeedAreIndependent =
false;
94 if (kit !=
nullptr && current_value == SampleRepeatMode::ONCE) {
96 sendNoteOffForKitArpeggiator(kit);
99 source.repeatMode = current_value;
104 uiNeedsRendering(&instrumentClipView, 0xFFFFFFFF, 0);
106 deluge::vector<std::string_view> getOptions(OptType optType)
override {
109 l10n::getView(l10n::String::STRING_FOR_CUT),
110 l10n::getView(l10n::String::STRING_FOR_ONCE),
111 l10n::getView(l10n::String::STRING_FOR_LOOP),
112 l10n::getView(l10n::String::STRING_FOR_STRETCH),
116 void renderInHorizontalMenu(int32_t startX, int32_t width, int32_t startY, int32_t height)
override {
117 const auto& source = soundEditor.currentSound->sources[source_id_];
118 const Icon& icon = [&] {
119 switch (source.repeatMode) {
120 case SampleRepeatMode::CUT:
121 return OLED::sampleModeCutIcon;
122 case SampleRepeatMode::ONCE:
123 return OLED::sampleModeOnceIcon;
124 case SampleRepeatMode::LOOP:
125 return OLED::sampleModeLoopIcon;
126 case SampleRepeatMode::STRETCH:
127 return OLED::sampleModeStretchIcon;
129 return OLED::sampleModeCutIcon;
131 OLED::main.drawIcon(icon, startX + 4, startY - 1);
134 void getColumnLabel(StringBuf& label)
override { label.append(getOptions(OptType::SHORT)[getValue()]); }
139 static void sendNoteOffForKitArpeggiator(Kit* kit) {
140 int32_t noteRowIndex;
141 NoteRow* noteRow = getCurrentInstrumentClip()->getNoteRowForDrum(kit->selectedDrum, ¬eRowIndex);
142 char modelStackMemory[MODEL_STACK_MAX_SIZE];
143 ModelStack* modelStack = (ModelStack*)modelStackMemory;
144 ModelStackWithThreeMainThings* modelStackWithThreeMainThings =
145 modelStack->addTimelineCounter(getCurrentClip())
146 ->addNoteRow(noteRowIndex, noteRow)
147 ->
addOtherTwoThings(soundEditor.currentModControllable, soundEditor.currentParamManager);
148 kit->noteOffPreKitArp(modelStackWithThreeMainThings, kit->selectedDrum);