aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/mptrack/SampleGenerator.h
blob: fb9a84abfa458edfc76022cb455c3007d2212a6c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
 * 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