winamp/Src/external_dependencies/openmpt-trunk/mptrack/SampleGenerator.h
2024-09-24 14:54:57 +02:00

208 lines
5.7 KiB
C++

/*
* SampleGenerator.h
* -----------------
* 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.
*/
#pragma once
#include "openmpt/all/BuildSettings.hpp"
#ifdef MPT_DISABLED_CODE
#include "Mptrack.h"
#include "Mainfrm.h"
#include "Sndfile.h"
#include "../muParser/include/muParser.h"
// sample length
#define SMPGEN_MINLENGTH 1
#define SMPGEN_MAXLENGTH MAX_SAMPLE_LENGTH
// sample frequency
#define SMPGEN_MINFREQ 1
#define SMPGEN_MAXFREQ 96000 // MAX_SAMPLE_RATE
// 16-bit sample quality - when changing this, also change CSampleGenerator::sampling_type and 16-bit flags in SampleGenerator.cpp!
#define SMPGEN_MIXBYTES 2
enum smpgen_clip_methods
{
smpgen_clip,
smpgen_overflow,
smpgen_normalize,
};
class CSampleGenerator
{
protected:
// sample parameters
static int sample_frequency;
static int sample_length;
static mu::string_type expression;
static smpgen_clip_methods sample_clipping;
// rendering helper variables (they're here for the callback functions)
static mu::value_type *sample_buffer;
static size_t samples_written;
typedef int16 sampling_type; // has to match SMPGEN_MIXBYTES!
static constexpr sampling_type sample_maxvalue = (1 << ((SMPGEN_MIXBYTES << 3) - 1)) - 1;
// muParser object for parsing the expression
mu::Parser muParser;
// Rendering callback functions
// functions
static mu::value_type ClipCallback(mu::value_type val, mu::value_type min, mu::value_type max) { return Clamp(val, min, max); };
static mu::value_type PWMCallback(mu::value_type pos, mu::value_type duty, mu::value_type width) { if(width == 0) return 0; else return (fmod(pos, width) < ((duty / 100) * width)) ? 1 : -1; };
static mu::value_type RndCallback(mu::value_type v) { return v * std::rand() / (mu::value_type)(RAND_MAX + 1.0); };
static mu::value_type SampleDataCallback(mu::value_type v);
static mu::value_type TriangleCallback(mu::value_type pos, mu::value_type width) { if((int)width == 0) return 0; else return std::abs(((int)pos % (int)(width)) - width / 2) / (width / 4) - 1; };
// binary operators
static mu::value_type ModuloCallback(mu::value_type x, mu::value_type y) { if(y == 0) return 0; else return fmod(x , y); };
void ShowError(mu::Parser::exception_type *e);
public:
bool ShowDialog();
bool TestExpression();
bool CanRenderSample() const;
bool RenderSample(CSoundFile *pSndFile, SAMPLEINDEX nSample);
CSampleGenerator();
};
//////////////////////////////////////////////////////////////////////////
// Sample Generator Formula Preset implementation
struct samplegen_expression
{
std::string description; // e.g. "Pulse"
mu::string_type expression; // e.g. "pwm(x,y,z)" - empty if this is a sub menu
};
#define MAX_SAMPLEGEN_PRESETS 100
class CSmpGenPresets
{
protected:
vector<samplegen_expression> presets;
public:
bool AddPreset(samplegen_expression new_preset) { if(GetNumPresets() >= MAX_SAMPLEGEN_PRESETS) return false; presets.push_back(new_preset); return true;};
bool RemovePreset(size_t which) { if(which < GetNumPresets()) { presets.erase(presets.begin() + which); return true; } else return false; };
samplegen_expression *GetPreset(size_t which) { if(which < GetNumPresets()) return &presets[which]; else return nullptr; };
size_t GetNumPresets() { return presets.size(); };
void Clear() { presets.clear(); };
CSmpGenPresets() { Clear(); }
~CSmpGenPresets() { Clear(); }
};
//////////////////////////////////////////////////////////////////////////
// Sample Generator Dialog implementation
class CSmpGenDialog: public CDialog
{
protected:
// sample parameters
int sample_frequency;
int sample_length;
double sample_seconds;
mu::string_type expression;
smpgen_clip_methods sample_clipping;
// pressed "OK"?
bool apply;
// preset slots
CSmpGenPresets presets;
HFONT hButtonFont; // "Marlett" font for "dropdown" button
void RecalcParameters(bool secondsChanged, bool forceRefresh = false);
// function presets
void CreateDefaultPresets();
public:
const int GetFrequency() { return sample_frequency; };
const int GetLength() { return sample_length; };
const smpgen_clip_methods GetClipping() { return sample_clipping; }
const mu::string_type GetExpression() { return expression; };
bool CanApply() { return apply; };
CSmpGenDialog(int freq, int len, smpgen_clip_methods clipping, mu::string_type expr):CDialog(IDD_SAMPLE_GENERATOR, CMainFrame::GetMainFrame())
{
sample_frequency = freq;
sample_length = len;
sample_clipping = clipping;
expression = expr;
apply = false;
}
protected:
virtual BOOL OnInitDialog();
virtual void OnOK();
virtual void OnCancel();
afx_msg void OnSampleLengthChanged();
afx_msg void OnSampleSecondsChanged();
afx_msg void OnSampleFreqChanged();
afx_msg void OnExpressionChanged();
afx_msg void OnShowExpressions();
afx_msg void OnShowPresets();
afx_msg void OnInsertExpression(UINT nId);
afx_msg void OnSelectPreset(UINT nId);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//////////////////////////////////////////////////////////////////////////
// Sample Generator Preset Dialog implementation
class CSmpGenPresetDlg: public CDialog
{
protected:
CSmpGenPresets *presets;
size_t currentItem; // first item is actually 1!
void RefreshList();
public:
CSmpGenPresetDlg(CSmpGenPresets *pPresets):CDialog(IDD_SAMPLE_GENERATOR_PRESETS, CMainFrame::GetMainFrame())
{
presets = pPresets;
currentItem = 0;
}
protected:
virtual BOOL OnInitDialog();
virtual void OnOK();
afx_msg void OnListSelChange();
afx_msg void OnTextChanged();
afx_msg void OnExpressionChanged();
afx_msg void OnAddPreset();
afx_msg void OnRemovePreset();
DECLARE_MESSAGE_MAP()
};
#endif // MPT_DISABLED_CODE