133323Sphk/* Copyright 2014 Haiku, Inc.
233323Sphk * Distributed under the terms of the MIT license.
333323Sphk */
433323Sphk
533323Sphk
633323Sphk#include <stdlib.h>
733323Sphk#include <vector>
833323Sphk
933396Sphk#include <Application.h>
1033323Sphk#include <Box.h>
1133323Sphk#include <CheckBox.h>
1233323Sphk#include <GroupLayout.h>
1333396Sphk#include <GroupView.h>
1433396Sphk#include <MediaDefs.h>
1533323Sphk#include <OptionPopUp.h>
1633323Sphk#include <TextControl.h>
1733323Sphk#include <Window.h>
1833323Sphk
1933323Sphk#include <Interpolate.h>
2033323Sphk#include <Resampler.h>
2133323Sphk
2233396Sphk
2333323Sphkstatic const int32 kMsgParametersChanged = 'pmch';
2433323Sphk
2533323Sphk
2633326Sphk// #pragma mark -
2733323Sphk
2833326Sphk
2933323Sphkclass Wave
3033396Sphk{
3133396Sphk	public:
3233396Sphk				Wave()
3333323Sphk					:
3433323Sphk					fData(NULL)
3533323Sphk				{ Resize(1); step = 1; }
3633323Sphk		float	ValueAt(int index) { return fData[index % fSize]; }
3733323Sphk		void	SetValue(int pos, float val) { fData[pos] = val; }
3833326Sphk		void	Resize(int newSize) {
3933323Sphk			if (newSize <= 0)
4033396Sphk				newSize = 1;
4133323Sphk			fData = (float*)realloc(fData, newSize * sizeof(float));
4233323Sphk			fSize = newSize;
4333323Sphk		}
4433323Sphk		int		Size() { return fSize; }
4533323Sphk		void*	Raw() { return fData; }
4633396Sphk
4733396Sphk		float step;
4833396Sphk	private:
4933396Sphk		float* fData;
5033323Sphk		int fSize;
5133396Sphk};
5233396Sphk
5333323Sphk
5433323Sphk// #pragma mark -
5533396Sphk
5633323Sphk
5733396Sphkclass WaveView: public BView
5833396Sphk{
5933396Sphk	public:
6033396Sphk				WaveView();
6133323Sphk
6233323Sphk		void	Draw(BRect update);
6333396Sphk
6433396Sphk		Wave	waves[3]; // reference, input, and output
6533323Sphk		float	zoom;
6633326Sphk};
6733323Sphk
6833323Sphk
6933323SphkWaveView::WaveView()
7033396Sphk	:
7133323Sphk	BView("wave", B_WILL_DRAW)
7233396Sphk{
7333323Sphk	SetExplicitMinSize(BSize(512, 256));
7433396Sphk}
7533323Sphk
7633323Sphk
7733326Sphkvoid
7833323SphkWaveView::Draw(BRect update)
7933323Sphk{
8033396Sphk	SetOrigin(0, 256);
8133323Sphk	SetPenSize(1);
8233396Sphk	for (float i = update.left; i <= update.right; i++) {
8333323Sphk		if (i < waves[0].Size())
8433396Sphk			SetHighColor(make_color(0, 0, 0, 255));
8533323Sphk		else
8633396Sphk			SetHighColor(make_color(180, 180, 180, 255));
8733396Sphk		BPoint p(i, waves[0].ValueAt(i) * zoom);
8833396Sphk		StrokeLine(p, p);
8933323Sphk	}
9033396Sphk
9133323Sphk	float i = 0;
9233323Sphk	float w1pos = 0;
9333323Sphk
9433396Sphk	// Skip the part outside the updat rect
9533323Sphk	while (w1pos <= update.left) {
9633323Sphk		w1pos += waves[1].step;
9733323Sphk		i++;
9833323Sphk	}
9933326Sphk
10033323Sphk	while (w1pos <= update.right) {
10133323Sphk		if (i < waves[1].Size())
10233323Sphk			SetHighColor(make_color(255, 0, 0, 255));
10333396Sphk		else
10433323Sphk			SetHighColor(make_color(255, 180, 180, 255));
10533326Sphk		BPoint p1(w1pos, INT16_MIN);
10633396Sphk		BPoint p2(w1pos, waves[1].ValueAt(i) * zoom);
10733323Sphk		StrokeLine(p1, p2);
10833326Sphk
10933323Sphk		w1pos += waves[1].step;
11033323Sphk		i++;
11133323Sphk	}
11233323Sphk
11333323Sphk	i = 0;
11433323Sphk	w1pos = 0;
11533396Sphk
11633323Sphk	// Skip the part outside the updat rect
11733396Sphk	while (w1pos <= update.left) {
11833323Sphk		w1pos += waves[2].step;
11933323Sphk		i++;
12033396Sphk	}
12133323Sphk
12233323Sphk	while (w1pos <= update.right) {
12333323Sphk		if (i < waves[2].Size())
12433323Sphk			SetHighColor(make_color(0, 255, 0, 255));
12533396Sphk		else
12633323Sphk			SetHighColor(make_color(180, 255, 180, 255));
12733323Sphk		BPoint p1(w1pos, INT16_MAX);
12833396Sphk		BPoint p2(w1pos, waves[2].ValueAt(i) * zoom);
12933323Sphk		StrokeLine(p1, p2);
13033323Sphk
13133323Sphk		w1pos += waves[2].step;
13233323Sphk		i++;
13333323Sphk	}
13433396Sphk
13533323Sphk}
13633396Sphk
13733323Sphk
13833396Sphk// #pragma mark -
13933323Sphk
14033323Sphk
14133323Sphkstatic BOptionPopUp* makeFormatMenu()
14233323Sphk{
14333396Sphk	BOptionPopUp* format = new BOptionPopUp("fmt", "Sample format:", NULL);
14433323Sphk	format->AddOptionAt("U8", media_raw_audio_format::B_AUDIO_UCHAR, 0);
14533323Sphk	format->AddOptionAt("S8", media_raw_audio_format::B_AUDIO_CHAR, 1);
14633323Sphk	format->AddOptionAt("S16", media_raw_audio_format::B_AUDIO_SHORT, 2);
14733323Sphk	format->AddOptionAt("S32", media_raw_audio_format::B_AUDIO_INT, 3);
14833323Sphk	format->AddOptionAt("F32", media_raw_audio_format::B_AUDIO_FLOAT, 4);
14933396Sphk
15033396Sphk	return format;
15133323Sphk}
15233323Sphk
15333323Sphk
15433323Sphkclass MainWindow: public BWindow
15533323Sphk{
15633323Sphk	public:
15733396Sphk				MainWindow();
15833323Sphk
15933323Sphk		void	MessageReceived(BMessage* what);
16033323Sphk
16133323Sphk	private:
16233323Sphk		BTextControl*	fInputRate;
16333323Sphk		BTextControl*	fOutputRate;
16433323Sphk		BCheckBox*		fInterpolate;
16533323Sphk
16633323Sphk		BTextControl*	fSignalVolume;
16733323Sphk		BTextControl*	fSignalFrequency;
16833323Sphk
16933323Sphk		WaveView*		fWaveView;
17033323Sphk};
17133323Sphk
17233323Sphk
17333323SphkMainWindow::MainWindow()
17433323Sphk	:
17533323Sphk	BWindow(BRect(100, 100, 400, 400), "Mixer test", B_DOCUMENT_WINDOW,
17633323Sphk		B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS)
17733323Sphk{
17833323Sphk	SetLayout(new BGroupLayout(B_VERTICAL));
17933396Sphk
18033323Sphk	BBox* inputGroup = new BBox("Input", 0, B_FANCY_BORDER);
18133396Sphk	inputGroup->SetLabel("Input");
18233323Sphk
18333323Sphk	BGroupView* inputs = new BGroupView(B_VERTICAL);
18433396Sphk	inputs->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING,
18533396Sphk		B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING);
18633323Sphk	inputGroup->AddChild(inputs);
18733323Sphk
18833323Sphk	fInputRate = new BTextControl("rate", "Sampling rate:", "256",
18933323Sphk		new BMessage(kMsgParametersChanged));
19033396Sphk	inputs->AddChild(fInputRate);
19133323Sphk#if 0
19233396Sphk	inputs->AddChild(makeFormatMenu());
19333323Sphk#endif
19433323Sphk
19533396Sphk	fSignalVolume = new BTextControl("vol", "Volume:", "127",
19633396Sphk		new BMessage(kMsgParametersChanged));
19733323Sphk	inputs->AddChild(fSignalVolume);
19833323Sphk	fSignalFrequency = new BTextControl("freq", "Signal freq:", "256",
19933323Sphk		new BMessage(kMsgParametersChanged));
20033396Sphk	inputs->AddChild(fSignalFrequency);
20133323Sphk
20233323Sphk	BBox* outputGroup = new BBox("Output", 0, B_FANCY_BORDER);
20333396Sphk	outputGroup->SetLabel("Output");
20433323Sphk
20533323Sphk	BGroupView* outputs = new BGroupView(B_VERTICAL);
20633323Sphk	outputs->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING,
20733396Sphk		B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING);
20833323Sphk	outputGroup->AddChild(outputs);
20933396Sphk
21033396Sphk	fOutputRate = new BTextControl("rate", "Sampling rate:", "256",
21133323Sphk		new BMessage(kMsgParametersChanged));
21233323Sphk	outputs->AddChild(fOutputRate);
21333323Sphk#if 0
21433396Sphk	outputs->AddChild(makeFormatMenu());
215	BTextControl* volume = new BTextControl("vol", "Gain:", "1", NULL);
216	outputs->AddChild(volume);
217#endif
218
219	fInterpolate = new BCheckBox("interp", "Interpolate",
220		new BMessage(kMsgParametersChanged));
221	outputs->AddChild(fInterpolate);
222
223	BGroupView* header = new BGroupView(B_HORIZONTAL);
224	AddChild(header);
225	header->GroupLayout()->SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING,
226		B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING);
227	header->AddChild(inputGroup);
228	header->AddChild(outputGroup);
229
230	AddChild(fWaveView = new WaveView());
231}
232
233
234void
235MainWindow::MessageReceived(BMessage* message)
236{
237	switch (message->what) {
238		case kMsgParametersChanged:
239		{
240			int freq = atoi(fSignalFrequency->Text());
241			fWaveView->waves[0].Resize(freq);
242
243			int irate = atoi(fInputRate->Text());
244			fWaveView->waves[1].Resize(irate);
245
246			int orate = atoi(fOutputRate->Text());
247			fWaveView->waves[2].Resize(orate);
248
249			int vol = atoi(fSignalVolume->Text());
250
251			fWaveView->waves[0].step = 1;
252			fWaveView->waves[1].step = (float)freq / irate;
253			fWaveView->waves[2].step = (float)freq / orate;
254			fWaveView->zoom = vol;
255
256			for (int i = 0; i < freq; i++) {
257				fWaveView->waves[0].SetValue(i, sinf(i * 2 * M_PI / freq));
258			}
259
260			for (int i = 0; i < irate; i++) {
261				fWaveView->waves[1].SetValue(i,
262					fWaveView->waves[0].ValueAt(i * freq / irate));
263			}
264
265			// FIXME handle gain
266			if (fInterpolate->Value() == B_CONTROL_ON) {
267				Interpolate sampler(media_raw_audio_format::B_AUDIO_FLOAT,
268					media_raw_audio_format::B_AUDIO_FLOAT);
269
270				// First call initializes the "old sample" in the interpolator.
271				// Since we do the interpolation on exactly one period of the
272				// sound wave, this works.
273				sampler.Resample(fWaveView->waves[1].Raw(), sizeof(float), irate,
274					fWaveView->waves[2].Raw(), sizeof(float), orate, 1);
275
276				sampler.Resample(fWaveView->waves[1].Raw(), sizeof(float), irate,
277					fWaveView->waves[2].Raw(), sizeof(float), orate, 1);
278			} else {
279				Resampler sampler(media_raw_audio_format::B_AUDIO_FLOAT,
280					media_raw_audio_format::B_AUDIO_FLOAT);
281
282				sampler.Resample(fWaveView->waves[1].Raw(), sizeof(float), irate,
283					fWaveView->waves[2].Raw(), sizeof(float), orate, 1);
284			}
285
286			fWaveView->Invalidate();
287			return;
288		}
289	}
290
291	BWindow::MessageReceived(message);
292}
293
294
295int main(int argc, char** argv)
296{
297	BApplication app("application/x-vnd.Haiku-MixerToy");
298	(new MainWindow())->Show();
299	app.Run();
300}
301