34class Type final :
public Selection,
public FormattedTitle {
36 Type(l10n::String name, l10n::String title_format_str, uint8_t source_id)
37 :
Selection(name), FormattedTitle(title_format_str, source_id + 1), sourceId_{source_id} {};
40 bool mayUseDx()
const {
return !soundEditor.editingKit() && sourceId_ == 0; }
43 int32_t rawVal =
static_cast<int32_t
>(soundEditor.currentSound->sources[sourceId_].oscType);
44 if (!mayUseDx() && rawVal >
static_cast<int32_t
>(OscType::DX7)) {
49 void writeCurrentValue()
override {
50 OscType oldValue = soundEditor.currentSound->sources[sourceId_].oscType;
51 auto newValue = getValue<OscType>();
52 if (!mayUseDx() &&
static_cast<int32_t
>(newValue) >=
static_cast<int32_t
>(OscType::DX7)) {
53 newValue =
static_cast<OscType
>(
static_cast<int32_t
>(newValue) + 1);
56 const auto needs_unassignment = {
59 OscType::INPUT_STEREO,
67 if (util::one_of(oldValue, needs_unassignment) || util::one_of(newValue, needs_unassignment)) {
68 soundEditor.currentSound->killAllVoices();
71 soundEditor.currentSound->sources[sourceId_].setOscType(newValue);
73 if (oldValue == OscType::SQUARE || newValue == OscType::SQUARE) {
74 soundEditor.currentSound->setupPatchingForAllParamManagers(currentSong);
78 [[nodiscard]] std::string_view
getTitle()
const override {
return FormattedTitle::title(); }
80 deluge::vector<std::string_view> getOptions(OptType optType)
override {
82 using enum l10n::String;
83 deluge::vector options = {
84 l10n::getView(STRING_FOR_SINE),
85 l10n::getView(STRING_FOR_TRIANGLE),
86 l10n::getView(STRING_FOR_SQUARE),
87 l10n::getView(STRING_FOR_ANALOG_SQUARE),
88 l10n::getView(STRING_FOR_SAW),
89 l10n::getView(STRING_FOR_ANALOG_SAW),
90 l10n::getView(STRING_FOR_WAVETABLE),
93 if (soundEditor.currentSound->getSynthMode() == SynthMode::RINGMOD) {
97 options.emplace_back(l10n::getView(STRING_FOR_SAMPLE));
100 options.emplace_back(l10n::getView(STRING_FOR_DX7));
103 if (AudioEngine::micPluggedIn || AudioEngine::lineInPluggedIn) {
104 options.emplace_back(l10n::getView(STRING_FOR_INPUT_LEFT));
105 options.emplace_back(l10n::getView(STRING_FOR_INPUT_RIGHT));
106 options.emplace_back(l10n::getView(STRING_FOR_INPUT_STEREO));
109 options.emplace_back(l10n::getView(STRING_FOR_INPUT));
116 Sound* sound =
static_cast<Sound*
>(modControllable);
117 return (sound->getSynthMode() != SynthMode::FM);
121 if (soundEditor.currentSound->sources[sourceId_].oscType != OscType::DX7) {
129 void renderInHorizontalMenu(int32_t startX, int32_t width, int32_t startY, int32_t height)
override {
132 const OscType oscType = soundEditor.currentSound->sources[sourceId_].oscType;
133 if (oscType == OscType::DX7) {
134 const auto option = getOptions(OptType::FULL)[getValue()].data();
135 return image.drawStringCentered(option, startX, startY + kHorizontalMenuSlotYOffset + 5, kTextTitleSpacingX,
136 kTextTitleSizeY, width);
139 const Icon& icon = [&] {
142 return OLED::sineIcon;
143 case OscType::TRIANGLE:
144 return OLED::triangleIcon;
145 case OscType::SQUARE:
146 case OscType::ANALOG_SQUARE:
147 return OLED::squareIcon;
149 case OscType::ANALOG_SAW_2:
150 return OLED::sawIcon;
151 case OscType::SAMPLE:
152 return OLED::sampleIcon;
153 case OscType::INPUT_STEREO:
154 case OscType::INPUT_L:
155 case OscType::INPUT_R:
156 return AudioEngine::lineInPluggedIn ? OLED::inputIcon : OLED::micIcon;
157 case OscType::WAVETABLE:
158 return OLED::wavetableIcon;
160 return OLED::sineIcon;
164 image.drawIconCentered(icon, startX, width, startY + kHorizontalMenuSlotYOffset + 2);
166 if (oscType == OscType::ANALOG_SQUARE || oscType == OscType::ANALOG_SAW_2) {
167 const int32_t x = startX + 4;
168 constexpr int32_t y = OLED_MAIN_HEIGHT_PIXELS - kTextSpacingY - 8;
169 image.clearAreaExact(x - 1, y - 1, x + kTextSpacingX + 1, y + kTextSpacingY + 1);
170 image.drawChar(
'A', x, y, kTextSpacingX, kTextSpacingY);
175 return parent !=
nullptr && parent->renderingStyle() == Submenu::RenderingStyle::HORIZONTAL;