123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737 |
- /*
- * SampleGenerator.cpp
- * -------------------
- * Purpose: Generate samples from math formulas using muParser
- * Notes : (currently none)
- * Authors: OpenMPT Devs
- * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
- */
- #include "stdafx.h"
- #if MPT_DISABLED_CODE
- #include "SampleGenerator.h"
- #include "modsmp_ctrl.h"
- int CSampleGenerator::sample_frequency = 44100;
- int CSampleGenerator::sample_length = CSampleGenerator::sample_frequency;
- mu::string_type CSampleGenerator::expression = _T("sin(xp * _pi)");
- smpgen_clip_methods CSampleGenerator::sample_clipping = smpgen_normalize;
- mu::value_type *CSampleGenerator::sample_buffer = nullptr;
- size_t CSampleGenerator::samples_written = 0;
- CSampleGenerator::CSampleGenerator()
- {
- // Setup function callbacks
- muParser.DefineFun(_T("clip"), &ClipCallback, false);
- muParser.DefineFun(_T("pwm"), &PWMCallback, false);
- muParser.DefineFun(_T("rnd"), &RndCallback, false);
- muParser.DefineFun(_T("smp"), &SampleDataCallback, false);
- muParser.DefineFun(_T("tri"), &TriangleCallback, false);
- // Setup binary operator callbacks
- muParser.DefineOprt(_T("mod"), &ModuloCallback, 0);
- //muParser.DefineConst("pi", (mu::value_type)PARSER_CONST_PI);
- }
- // Open the smpgen dialog
- bool CSampleGenerator::ShowDialog()
- {
- bool isDone = false, result = false;
- while(!isDone)
- {
- CSmpGenDialog dlg(sample_frequency, sample_length, sample_clipping, expression);
- dlg.DoModal();
- // pressed "OK" button?
- if(dlg.CanApply())
- {
- sample_frequency = dlg.GetFrequency();
- sample_length = dlg.GetLength();
- sample_clipping = dlg.GetClipping();
- expression = dlg.GetExpression();
- isDone = CanRenderSample();
- if(isDone) isDone = TestExpression(); // show dialog again if the formula can't be parsed.
- result = true;
- } else
- {
- isDone = true; // just quit.
- result = false;
- }
- }
- return result;
- }
- // Check if the currently select expression can be parsed by muParser.
- bool CSampleGenerator::TestExpression()
- {
- // reset helper variables
- samples_written = 0;
- sample_buffer = nullptr;
- muParser.SetExpr(expression);
- mu::value_type x = 0;
- muParser.DefineVar(_T("x"), &x);
- muParser.DefineVar(_T("xp"), &x);
- muParser.DefineVar(_T("len"), &x);
- muParser.DefineVar(_T("lens"), &x);
- muParser.DefineVar(_T("freq"), &x);
- try
- {
- muParser.Eval();
- }
- catch (mu::Parser::exception_type &e)
- {
- ShowError(&e);
- return false;
- }
- return true;
- }
- // Check if sample parameters are valid.
- bool CSampleGenerator::CanRenderSample() const
- {
- if(sample_frequency < SMPGEN_MINFREQ || sample_frequency > SMPGEN_MAXFREQ || sample_length < SMPGEN_MINLENGTH || sample_length > SMPGEN_MAXLENGTH) return false;
- return true;
- }
- // Actual render loop.
- bool CSampleGenerator::RenderSample(CSoundFile *pSndFile, SAMPLEINDEX nSample)
- {
- if(!CanRenderSample() || !TestExpression() || (pSndFile == nullptr) || (nSample < 1) || (nSample > pSndFile->m_nSamples)) return false;
- // allocate a new buffer
- sample_buffer = (mu::value_type *)malloc(sample_length * sizeof(mu::value_type));
- if(sample_buffer == nullptr) return false;
- memset(sample_buffer, 0, sample_length * sizeof(mu::value_type));
- mu::value_type x = 0, xp = 0;
- mu::value_type v_len = sample_length, v_freq = sample_frequency, v_lens = v_len / v_freq;
- muParser.DefineVar(_T("x"), &x);
- muParser.DefineVar(_T("xp"), &xp);
- muParser.DefineVar(_T("len"), &v_len);
- muParser.DefineVar(_T("lens"), &v_lens);
- muParser.DefineVar(_T("freq"), &v_freq);
- bool success = true;
- mu::value_type minmax = 0;
- for(size_t i = 0; i < (size_t)sample_length; i++)
- {
- samples_written = i;
- x = (mu::value_type)i;
- xp = x * 100 / sample_length;
- try
- {
- sample_buffer[i] = muParser.Eval();
- }
- catch (mu::Parser::exception_type &e)
- {
- // let's just ignore div by zero errors (note: this error code is currently unused (muParser 1.30))
- if(e.GetCode() != mu::ecDIV_BY_ZERO)
- {
- ShowError(&e);
- success = false;
- break;
- }
- sample_buffer[i] = 0;
- }
- // new maximum value?
- if(std::abs(sample_buffer[i]) > minmax) minmax = std::abs(sample_buffer[i]);
- }
- if(success)
- {
- MODSAMPLE *pModSample = &pSndFile->Samples[nSample];
- BEGIN_CRITICAL();
- // first, save some memory... (leads to crashes)
- //CSoundFile::FreeSample(pModSample->pSample);
- //pModSample->pSample = nullptr;
- if(minmax == 0) minmax = 1; // avoid division by 0
- // convert sample to 16-bit (or whateve rhas been specified)
- int16 *pSample = (sampling_type *)CSoundFile::AllocateSample((sample_length + 4) * SMPGEN_MIXBYTES);
- for(size_t i = 0; i < (size_t)sample_length; i++)
- {
- switch(sample_clipping)
- {
- case smpgen_clip: sample_buffer[i] = CLAMP(sample_buffer[i], -1, 1); break; // option 1: clip
- case smpgen_normalize: sample_buffer[i] /= minmax; break; // option 3: normalize
- }
- pSample[i] = (sampling_type)(sample_buffer[i] * sample_maxvalue);
- }
- // set new sample proprerties
- pModSample->nC5Speed = sample_frequency;
- CSoundFile::FrequencyToTranspose(pModSample);
- pModSample->uFlags |= CHN_16BIT; // has to be adjusted if SMPGEN_MIXBYTES changes!
- pModSample->uFlags &= ~(CHN_STEREO|CHN_SUSTAINLOOP|CHN_PINGPONGSUSTAIN);
- pModSample->nLoopStart = 0;
- pModSample->nLoopEnd = sample_length;
- pModSample->nSustainStart = pModSample->nSustainEnd = 0;
- if(sample_length / sample_frequency < 5) // arbitrary limit for automatic sample loop (5 seconds)
- pModSample->uFlags |= CHN_LOOP;
- else
- pModSample->uFlags &= ~(CHN_LOOP|CHN_PINGPONGLOOP);
- ctrlSmp::ReplaceSample(*pModSample, (LPSTR)pSample, sample_length, pSndFile);
- END_CRITICAL();
- }
- free(sample_buffer);
- sample_buffer = nullptr;
- return success;
- }
- // Callback function to access sample data
- mu::value_type CSampleGenerator::SampleDataCallback(mu::value_type v)
- {
- if(sample_buffer == nullptr) return 0;
- v = CLAMP(v, 0, samples_written);
- size_t pos = static_cast<size_t>(v);
- return sample_buffer[pos];
- }
- void CSampleGenerator::ShowError(mu::Parser::exception_type *e)
- {
- std::string errmsg;
- errmsg = "The expression\n " + e->GetExpr() + "\ncontains an error ";
- if(!e->GetToken().empty())
- errmsg += "in the token\n " + e->GetToken() + "\n";
- errmsg += "at position " + Stringify(e->GetPos()) + ".\nThe error message was: " + e->GetMsg();
- ::MessageBox(0, errmsg.c_str(), _T("muParser Sample Generator"), 0);
- }
- //////////////////////////////////////////////////////////////////////////
- // Sample Generator Dialog implementation
- #define MAX_SAMPLEGEN_EXPRESSIONS 61
- BEGIN_MESSAGE_MAP(CSmpGenDialog, CDialog)
- ON_EN_CHANGE(IDC_EDIT_SAMPLE_LENGTH, &CSmpGenDialog::OnSampleLengthChanged)
- ON_EN_CHANGE(IDC_EDIT_SAMPLE_LENGTH_SEC, &CSmpGenDialog::OnSampleSecondsChanged)
- ON_EN_CHANGE(IDC_EDIT_SAMPLE_FREQ, &CSmpGenDialog::OnSampleFreqChanged)
- ON_EN_CHANGE(IDC_EDIT_FORMULA, &CSmpGenDialog::OnExpressionChanged)
- ON_COMMAND(IDC_BUTTON_SHOW_EXPRESSIONS, &CSmpGenDialog::OnShowExpressions)
- ON_COMMAND(IDC_BUTTON_SAMPLEGEN_PRESETS, &CSmpGenDialog::OnShowPresets)
- ON_COMMAND_RANGE(ID_SAMPLE_GENERATOR_MENU, ID_SAMPLE_GENERATOR_MENU + MAX_SAMPLEGEN_EXPRESSIONS - 1, &CSmpGenDialog::OnInsertExpression)
- ON_COMMAND_RANGE(ID_SAMPLE_GENERATOR_PRESET_MENU, ID_SAMPLE_GENERATOR_PRESET_MENU + MAX_SAMPLEGEN_PRESETS + 1, &CSmpGenDialog::OnSelectPreset)
- END_MESSAGE_MAP()
- // List of all possible expression for expression menu
- const samplegen_expression menu_descriptions[MAX_SAMPLEGEN_EXPRESSIONS] =
- {
- {"Variables", ""},
- {"Current position (sampling point)", "x"},
- {"Current position (percentage)", "xp"},
- {"Sample length", "len"},
- {"Sample length (seconds)", "lens"},
- {"Sampling frequency", "freq"},
- {"Constants", ""},
- {"Pi", "_pi"},
- {"e", "_e"},
- {"Trigonometric functions", ""},
- {"Sine", "sin(x)"},
- {"Cosine", "cos(x)"},
- {"Tangens", "tan(x)"},
- {"Arcus Sine", "asin(x)"},
- {"Arcus Cosine", "acos(x)"},
- {"Arcus Tangens", "atan(x)"},
- {"Hyperbolic Sine", "sinh(x)"},
- {"Hyperbolic Cosine", "cosh(x)"},
- {"Hyperbolic Tangens", "tanh(x)"},
- {"Hyperbolic Arcus Sine", "asinh(x)"},
- {"Hyperbolic Arcus Cosine", "acosh(x)"},
- {"Hyperbolic Arcus Tangens", "atanh(x)"},
- {"Log, Exp, Root", ""},
- {"Logarithm (base 2)", "log2(x)"},
- {"Logarithm (base 10)", "log(x)"},
- {"Natural Logarithm (base e)", "ln(x)"},
- {"e^x", "exp(x)"},
- {"Square Root", "sqrt(x)"},
- {"Sign and rounding", ""},
- {"Sign", "sign(x)"},
- {"Absolute value", "abs(x)"},
- {"Round to nearest integer", "rint(x)"},
- {"Sets", ""},
- {"Minimum", "min(x, y, ...)"},
- {"Maximum", "max(x, y, ...)"},
- {"Sum", "sum(x, y, ...)"},
- {"Mean value", "avg(x, y, ...)"},
- {"Misc functions", ""},
- {"Pulse generator", "pwm(position, duty%, width)"},
- {"Triangle", "tri(position, width)"},
- {"Random value between 0 and x", "rnd(x)"},
- {"Access previous sampling point", "smp(position)"},
- {"Clip between values", "clip(value, minclip, maxclip)"},
- {"If...Then...Else", "if(condition, statement1, statement2)"},
- {"Operators", ""},
- {"Assignment", "x = y"},
- {"Logical And", "x abd y"},
- {"Logical Or", "x or y"},
- {"Logical Xor", "x xor y"},
- {"Less or equal", "x <= y"},
- {"Greater or equal", "x >= y"},
- {"Not equal", "x != y"},
- {"Equal", "x == y"},
- {"Greater than", "x > y"},
- {"Less than", "x < y"},
- {"Addition", "x + y"},
- {"Subtraction", "x - y"},
- {"Multiplication", "x * y"},
- {"Division", "x / y"},
- {"x^y", "x ^ y"},
- {"Modulo", "x mod y"},
- };
- BOOL CSmpGenDialog::OnInitDialog()
- {
- CDialog::OnInitDialog();
- RecalcParameters(false, true);
- SetDlgItemText(IDC_EDIT_FORMULA, expression.c_str());
- int check = IDC_RADIO_SMPCLIP1;
- switch(sample_clipping)
- {
- case smpgen_clip: check = IDC_RADIO_SMPCLIP1; break;
- case smpgen_overflow: check = IDC_RADIO_SMPCLIP2; break;
- case smpgen_normalize: check = IDC_RADIO_SMPCLIP3; break;
- }
- CheckRadioButton(IDC_RADIO_SMPCLIP1, IDC_RADIO_SMPCLIP3, check);
- if(presets.GetNumPresets() == 0)
- {
- CreateDefaultPresets();
- }
- // Create font for "dropdown" button (Marlett system font)
- hButtonFont = CreateFont(14, 0, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_DONTCARE, TEXT("Marlett"));
- ::SendMessage(GetDlgItem(IDC_BUTTON_SHOW_EXPRESSIONS)->m_hWnd, WM_SETFONT, (WPARAM)hButtonFont, MAKELPARAM(TRUE, 0));
- return TRUE;
- }
- void CSmpGenDialog::OnOK()
- {
- CDialog::OnOK();
- apply = true;
- int check = GetCheckedRadioButton(IDC_RADIO_SMPCLIP1, IDC_RADIO_SMPCLIP3);
- switch(check)
- {
- case IDC_RADIO_SMPCLIP1: sample_clipping = smpgen_clip; break;
- case IDC_RADIO_SMPCLIP2: sample_clipping = smpgen_overflow; break;
- case IDC_RADIO_SMPCLIP3: sample_clipping = smpgen_normalize; break;
- }
- DeleteObject(hButtonFont);
- }
- void CSmpGenDialog::OnCancel()
- {
- CDialog::OnCancel();
- apply = false;
- }
- // User changed formula
- void CSmpGenDialog::OnExpressionChanged()
- {
- CString result;
- GetDlgItemText(IDC_EDIT_FORMULA, result);
- expression = result;
- }
- // User changed sample length field
- void CSmpGenDialog::OnSampleLengthChanged()
- {
- int temp_length = GetDlgItemInt(IDC_EDIT_SAMPLE_LENGTH);
- if(temp_length >= SMPGEN_MINLENGTH && temp_length <= SMPGEN_MAXLENGTH)
- {
- sample_length = temp_length;
- RecalcParameters(false);
- }
- }
- // User changed sample length (seconds) field
- void CSmpGenDialog::OnSampleSecondsChanged()
- {
- CString str;
- GetDlgItemText(IDC_EDIT_SAMPLE_LENGTH_SEC, str);
- double temp_seconds = atof(str);
- if(temp_seconds > 0)
- {
- sample_seconds = temp_seconds;
- RecalcParameters(true);
- }
- }
- // User changed sample frequency field
- void CSmpGenDialog::OnSampleFreqChanged()
- {
- int temp_freq = GetDlgItemInt(IDC_EDIT_SAMPLE_FREQ);
- if(temp_freq >= SMPGEN_MINFREQ && temp_freq <= SMPGEN_MAXFREQ)
- {
- sample_frequency = temp_freq;
- RecalcParameters(false);
- }
- }
- // Show all expressions that can be input
- void CSmpGenDialog::OnShowExpressions()
- {
- HMENU hMenu = ::CreatePopupMenu(), hSubMenu = NULL;
- if(!hMenu) return;
- for(int i = 0; i < MAX_SAMPLEGEN_EXPRESSIONS; i++)
- {
- if(menu_descriptions[i].expression == "")
- {
- // add sub menu
- if(hSubMenu != NULL) ::DestroyMenu(hSubMenu);
- hSubMenu = ::CreatePopupMenu();
- AppendMenu(hMenu, MF_POPUP, (UINT_PTR)hSubMenu, menu_descriptions[i].description.c_str());
- } else
- {
- // add sub menu entry (formula)
- AppendMenu(hSubMenu, MF_STRING, ID_SAMPLE_GENERATOR_MENU + i, menu_descriptions[i].description.c_str());
- }
- }
- // place popup menu below button
- RECT button;
- GetDlgItem(IDC_BUTTON_SHOW_EXPRESSIONS)->GetWindowRect(&button);
- ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, button.left, button.bottom, 0, m_hWnd, NULL);
- ::DestroyMenu(hMenu);
- ::DestroyMenu(hSubMenu);
- }
- // Show all expression presets
- void CSmpGenDialog::OnShowPresets()
- {
- HMENU hMenu = ::CreatePopupMenu();
- if(!hMenu) return;
- bool prestsExist = false;
- for(size_t i = 0; i < presets.GetNumPresets(); i++)
- {
- if(presets.GetPreset(i)->expression != "")
- {
- AppendMenu(hMenu, MF_STRING, ID_SAMPLE_GENERATOR_PRESET_MENU + i, presets.GetPreset(i)->description.c_str());
- prestsExist = true;
- }
- }
-
- if(prestsExist) AppendMenu(hMenu, MF_SEPARATOR, 0, NULL);
- AppendMenu(hMenu, MF_STRING, ID_SAMPLE_GENERATOR_PRESET_MENU + MAX_SAMPLEGEN_PRESETS, _TEXT("Manage..."));
- CString result;
- GetDlgItemText(IDC_EDIT_FORMULA, result);
- if((!result.IsEmpty()) && (presets.GetNumPresets() < MAX_SAMPLEGEN_PRESETS))
- {
- AppendMenu(hMenu, MF_STRING, ID_SAMPLE_GENERATOR_PRESET_MENU + MAX_SAMPLEGEN_PRESETS + 1, _TEXT("Add current..."));
- }
- // place popup menu below button
- RECT button;
- GetDlgItem(IDC_BUTTON_SAMPLEGEN_PRESETS)->GetWindowRect(&button);
- ::TrackPopupMenu(hMenu, TPM_LEFTALIGN | TPM_RIGHTBUTTON, button.left, button.bottom, 0, m_hWnd, NULL);
- ::DestroyMenu(hMenu);
- }
- // Insert expression from context menu
- void CSmpGenDialog::OnInsertExpression(UINT nId)
- {
- if((nId < ID_SAMPLE_GENERATOR_MENU) || (nId >= ID_SAMPLE_GENERATOR_MENU + MAX_SAMPLEGEN_EXPRESSIONS)) return;
- expression += " " + menu_descriptions[nId - ID_SAMPLE_GENERATOR_MENU].expression;
- SetDlgItemText(IDC_EDIT_FORMULA, expression.c_str());
- }
- // Select a preset (or manage them, or add one)
- void CSmpGenDialog::OnSelectPreset(UINT nId)
- {
- if((nId < ID_SAMPLE_GENERATOR_PRESET_MENU) || (nId >= ID_SAMPLE_GENERATOR_PRESET_MENU + MAX_SAMPLEGEN_PRESETS + 2)) return;
- if(nId - ID_SAMPLE_GENERATOR_PRESET_MENU >= MAX_SAMPLEGEN_PRESETS)
- {
- // add...
- if((nId - ID_SAMPLE_GENERATOR_PRESET_MENU == MAX_SAMPLEGEN_PRESETS + 1))
- {
- samplegen_expression newPreset;
- newPreset.description = newPreset.expression = expression;
- presets.AddPreset(newPreset);
- // call preset manager now.
- }
- // manage...
- CSmpGenPresetDlg dlg(&presets);
- dlg.DoModal();
- } else
- {
- expression = presets.GetPreset(nId - ID_SAMPLE_GENERATOR_PRESET_MENU)->expression;
- SetDlgItemText(IDC_EDIT_FORMULA, expression.c_str());
- }
- }
- // Update input fields, depending on what has been chagned
- void CSmpGenDialog::RecalcParameters(bool secondsChanged, bool forceRefresh)
- {
- static bool isLocked = false;
- if(isLocked) return;
- isLocked = true; // avoid deadlock
- if(secondsChanged)
- {
- // seconds changed => recalc length
- sample_length = (int)(sample_seconds * sample_frequency);
- if(sample_length < SMPGEN_MINLENGTH || sample_length > SMPGEN_MAXLENGTH) sample_length = SMPGEN_MAXLENGTH;
- } else
- {
- // length/freq changed => recalc seconds
- sample_seconds = ((double)sample_length) / ((double)sample_frequency);
- }
- if(secondsChanged || forceRefresh) SetDlgItemInt(IDC_EDIT_SAMPLE_LENGTH, sample_length);
- if(secondsChanged || forceRefresh) SetDlgItemInt(IDC_EDIT_SAMPLE_FREQ, sample_frequency);
- CString str;
- str.Format("%.4f", sample_seconds);
- if(!secondsChanged || forceRefresh) SetDlgItemText(IDC_EDIT_SAMPLE_LENGTH_SEC, str);
- int smpsize = sample_length * SMPGEN_MIXBYTES;
- if(smpsize < 1024)
- {
- str.Format("Sample Size: %d Bytes", smpsize);
- } else if((smpsize >> 10) < 1024)
- {
- str.Format("Sample Size: %d KB", smpsize >> 10);
- } else
- {
- str.Format("Sample Size: %d MB", smpsize >> 20);
- }
- SetDlgItemText(IDC_STATIC_SMPSIZE_KB, str);
- isLocked = false;
- }
- // Create a set of default formla presets
- void CSmpGenDialog::CreateDefaultPresets()
- {
- samplegen_expression preset;
- preset.description = "A440";
- preset.expression = "sin(xp * _pi / 50 * 440 * len / freq)";
- presets.AddPreset(preset);
- preset.description = "Brown Noise (kind of)";
- preset.expression = "rnd(1) * 0.1 + smp(x - 1) * 0.9";
- presets.AddPreset(preset);
- preset.description = "Noisy Saw";
- preset.expression = "(x mod 800) / 800 - 0.5 + rnd(0.1)";
- presets.AddPreset(preset);
- preset.description = "PWM Filter";
- preset.expression = "pwm(x, 50 + sin(xp * _pi / 100) * 40, 100) + tri(x, 50)";
- presets.AddPreset(preset);
-
- preset.description = "Fat PWM Pad";
- preset.expression = "pwm(x, xp, 500) + pwm(x, abs(50 - xp), 1000)";
- presets.AddPreset(preset);
- preset.description = "Dual Square";
- preset.expression = "if((x mod 100) < 50, (x mod 200), -x mod 200)";
- presets.AddPreset(preset);
- preset.description = "Noise Hit";
- preset.expression = "exp(-xp) * (rnd(x) - x / 2)";
- presets.AddPreset(preset);
- preset.description = "Laser";
- preset.expression = "sin(xp * _pi * 100 /(xp ^ 2)) * 100 / sqrt(xp)";
- presets.AddPreset(preset);
- preset.description = "Noisy Laser Hit";
- preset.expression = "(sin(sqrt(xp) * 100) + rnd(1) - 0.5) * exp(-xp / 10)";
- presets.AddPreset(preset);
- preset.description = "Twinkle, Twinkle...";
- preset.expression = "sin(xp * _pi * 100 / xp) * 100 / sqrt(xp)";
- presets.AddPreset(preset);
- preset.description = "FM Tom";
- preset.expression = "sin(xp * _pi * 2 + (xp / 5 - 50) ^ 2) * exp(-xp / 10)";
- presets.AddPreset(preset);
- preset.description = "FM Warp";
- preset.expression = "sin(_pi * xp / 2 * (1 + (1 + sin(_pi * xp / 4 * 50)) / 4)) * exp(-(xp / 8) * .6)";
- presets.AddPreset(preset);
- preset.description = "Weird Noise";
- preset.expression = "rnd(1) * 0.1 + smp(x - rnd(xp)) * 0.9";
- presets.AddPreset(preset);
- }
- //////////////////////////////////////////////////////////////////////////
- // Sample Generator Preset Dialog implementation
- BEGIN_MESSAGE_MAP(CSmpGenPresetDlg, CDialog)
- ON_COMMAND(IDC_BUTTON_ADD, &CSmpGenPresetDlg::OnAddPreset)
- ON_COMMAND(IDC_BUTTON_REMOVE, &CSmpGenPresetDlg::OnRemovePreset)
- ON_EN_CHANGE(IDC_EDIT_PRESET_NAME, &CSmpGenPresetDlg::OnTextChanged)
- ON_EN_CHANGE(IDC_EDIT_PRESET_EXPR, &CSmpGenPresetDlg::OnExpressionChanged)
- ON_LBN_SELCHANGE(IDC_LIST_SAMPLEGEN_PRESETS, &CSmpGenPresetDlg::OnListSelChange)
- END_MESSAGE_MAP()
- BOOL CSmpGenPresetDlg::OnInitDialog()
- {
- CDialog::OnInitDialog();
- RefreshList();
- return TRUE;
- }
- void CSmpGenPresetDlg::OnOK()
- {
- // remove empty presets
- for(size_t i = 0; i < presets->GetNumPresets(); i++)
- {
- if(presets->GetPreset(i)->expression.empty())
- {
- presets->RemovePreset(i);
- }
- }
- CDialog::OnOK();
- }
- void CSmpGenPresetDlg::OnListSelChange()
- {
- currentItem = ((CListBox *)GetDlgItem(IDC_LIST_SAMPLEGEN_PRESETS))->GetCurSel() + 1;
- if(currentItem == 0 || currentItem > presets->GetNumPresets()) return;
- samplegen_expression *preset = presets->GetPreset(currentItem - 1);
- if(preset == nullptr) return;
- SetDlgItemText(IDC_EDIT_PRESET_NAME, preset->description.c_str());
- SetDlgItemText(IDC_EDIT_PRESET_EXPR, preset->expression.c_str());
- }
- void CSmpGenPresetDlg::OnTextChanged()
- {
- if(currentItem == 0 || currentItem > presets->GetNumPresets()) return;
- CString result;
- GetDlgItemText(IDC_EDIT_PRESET_NAME, result);
- samplegen_expression *preset = presets->GetPreset(currentItem - 1);
- if(preset == nullptr) return;
- preset->description = result;
- CListBox *clist = (CListBox *)GetDlgItem(IDC_LIST_SAMPLEGEN_PRESETS);
- clist->DeleteString(currentItem - 1);
- clist->InsertString(currentItem - 1, (preset->description).c_str());
- clist->SetCurSel(currentItem - 1);
- }
- void CSmpGenPresetDlg::OnExpressionChanged()
- {
- if(currentItem == 0 || currentItem > presets->GetNumPresets()) return;
- CString result;
- GetDlgItemText(IDC_EDIT_PRESET_EXPR, result);
- samplegen_expression *preset = presets->GetPreset(currentItem - 1);
- if(preset != nullptr) preset->expression = result;
- }
- void CSmpGenPresetDlg::OnAddPreset()
- {
- samplegen_expression newPreset;
- newPreset.description = "New Preset";
- newPreset.expression = "";
- if(presets->AddPreset(newPreset))
- {
- currentItem = presets->GetNumPresets();
- RefreshList();
- }
- }
- void CSmpGenPresetDlg::OnRemovePreset()
- {
- if(currentItem == 0 || currentItem > presets->GetNumPresets()) return;
- if(presets->RemovePreset(currentItem - 1))
- RefreshList();
- }
- void CSmpGenPresetDlg::RefreshList()
- {
- CListBox *clist = (CListBox *)GetDlgItem(IDC_LIST_SAMPLEGEN_PRESETS);
- clist->SetRedraw(FALSE); //disable lisbox refreshes during fill to avoid flicker
- clist->ResetContent();
- for(size_t i = 0; i < presets->GetNumPresets(); i++)
- {
- samplegen_expression *preset = presets->GetPreset(i);
- if(preset != nullptr)
- clist->AddString((preset->description).c_str());
- }
- clist->SetRedraw(TRUE); //re-enable lisbox refreshes
- if(currentItem == 0 || currentItem > presets->GetNumPresets())
- {
- currentItem = presets->GetNumPresets();
- }
- if(currentItem != 0) clist->SetCurSel(currentItem - 1);
- OnListSelChange();
- }
- #endif // MPT_DISABLED_CODE
|