From 258fbe371b6ca5b43c73a698470fe96fceda2672 Mon Sep 17 00:00:00 2001 From: Adrien Destugues Date: Mon, 8 Dec 2014 18:10:31 +0100 Subject: [PATCH] MixerToy: app for testing mixer resamplers. * Shows a source wave (black), a sampled version of it (red), and a resampled version of that using the mixer (green). * Debugging tool for #9438. Shows that the drop/repeat resampler is working ok, but interpolate is quite broken. --- src/tests/add-ons/media/Jamfile | 1 + src/tests/add-ons/media/media-add-ons/Jamfile | 4 + .../add-ons/media/media-add-ons/mixer/Jamfile | 16 + .../media/media-add-ons/mixer/main.cpp | 293 ++++++++++++++++++ 4 files changed, 314 insertions(+) create mode 100644 src/tests/add-ons/media/media-add-ons/Jamfile create mode 100644 src/tests/add-ons/media/media-add-ons/mixer/Jamfile create mode 100644 src/tests/add-ons/media/media-add-ons/mixer/main.cpp diff --git a/src/tests/add-ons/media/Jamfile b/src/tests/add-ons/media/Jamfile index 9bdac447e3..be7ba9cfea 100644 --- a/src/tests/add-ons/media/Jamfile +++ b/src/tests/add-ons/media/Jamfile @@ -1,3 +1,4 @@ SubDir HAIKU_TOP src tests add-ons media ; SubInclude HAIKU_TOP src tests add-ons media plugins ; +SubInclude HAIKU_TOP src tests add-ons media media-add-ons ; diff --git a/src/tests/add-ons/media/media-add-ons/Jamfile b/src/tests/add-ons/media/media-add-ons/Jamfile new file mode 100644 index 0000000000..4956cf70ad --- /dev/null +++ b/src/tests/add-ons/media/media-add-ons/Jamfile @@ -0,0 +1,4 @@ +SubDir HAIKU_TOP src tests add-ons media media-add-ons ; + +SubInclude HAIKU_TOP src tests add-ons media media-add-ons mixer ; + diff --git a/src/tests/add-ons/media/media-add-ons/mixer/Jamfile b/src/tests/add-ons/media/media-add-ons/mixer/Jamfile new file mode 100644 index 0000000000..3c6bc0ccf0 --- /dev/null +++ b/src/tests/add-ons/media/media-add-ons/mixer/Jamfile @@ -0,0 +1,16 @@ +SubDir HAIKU_TOP src tests add-ons media media-add-ons mixer ; + +SubDirSysHdrs [ FDirName $(HAIKU_TOP) src add-ons media media-add-ons mixer ] ; + +SimpleTest mixerToy : + main.cpp + + Resampler.cpp + Interpolate.cpp + + : be +; + +# Tell Jam where to find these sources +SEARCH on [ FGristFiles Resampler.cpp Interpolate.cpp ] + = [ FDirName $(HAIKU_TOP) src add-ons media media-add-ons mixer ] ; diff --git a/src/tests/add-ons/media/media-add-ons/mixer/main.cpp b/src/tests/add-ons/media/media-add-ons/mixer/main.cpp new file mode 100644 index 0000000000..3caf843891 --- /dev/null +++ b/src/tests/add-ons/media/media-add-ons/mixer/main.cpp @@ -0,0 +1,293 @@ +/* Copyright 2014 Haiku, Inc. + * Distributed under the terms of the MIT license. + */ + + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static const int32 kMsgParametersChanged = 'pmch'; + + +// #pragma mark - + + +class Wave +{ + public: + Wave() + : + fData(NULL) + { Resize(1); step = 1; } + float ValueAt(int index) { return fData[index % fSize]; } + void SetValue(int pos, float val) { fData[pos] = val; } + void Resize(int newSize) { + if (newSize <= 0) + newSize = 1; + fData = (float*)realloc(fData, newSize * sizeof(float)); + fSize = newSize; + } + int Size() { return fSize; } + void* Raw() { return fData; } + + float step; + private: + float* fData; + int fSize; +}; + + +// #pragma mark - + + +class WaveView: public BView +{ + public: + WaveView(); + + void Draw(BRect update); + + Wave waves[3]; // reference, input, and output + float zoom; +}; + + +WaveView::WaveView() + : + BView("wave", B_WILL_DRAW) +{ + SetExplicitMinSize(BSize(512, 256)); +} + + +void +WaveView::Draw(BRect update) +{ + SetOrigin(0, 256); + SetPenSize(1); + for (float i = update.left; i <= update.right; i++) { + if (i < waves[0].Size()) + SetHighColor(make_color(0, 0, 0, 255)); + else + SetHighColor(make_color(180, 180, 180, 255)); + BPoint p(i, waves[0].ValueAt(i) * zoom); + StrokeLine(p, p); + } + + float i = 0; + float w1pos = 0; + + // Skip the part outside the updat rect + while (w1pos <= update.left) { + w1pos += waves[1].step; + i++; + } + + while (w1pos <= update.right) { + if (i < waves[1].Size()) + SetHighColor(make_color(255, 0, 0, 255)); + else + SetHighColor(make_color(255, 180, 180, 255)); + BPoint p1(w1pos, INT16_MIN); + BPoint p2(w1pos, waves[1].ValueAt(i) * zoom); + StrokeLine(p1, p2); + + w1pos += waves[1].step; + i++; + } + + i = 0; + w1pos = 0; + + // Skip the part outside the updat rect + while (w1pos <= update.left) { + w1pos += waves[2].step; + i++; + } + + while (w1pos <= update.right) { + if (i < waves[2].Size()) + SetHighColor(make_color(0, 255, 0, 255)); + else + SetHighColor(make_color(180, 255, 180, 255)); + BPoint p1(w1pos, INT16_MAX); + BPoint p2(w1pos, waves[2].ValueAt(i) * zoom); + StrokeLine(p1, p2); + + w1pos += waves[2].step; + i++; + } + +} + + +// #pragma mark - + + +static BOptionPopUp* makeFormatMenu() +{ + BOptionPopUp* format = new BOptionPopUp("fmt", "Sample format:", NULL); + format->AddOptionAt("U8", media_raw_audio_format::B_AUDIO_UCHAR, 0); + format->AddOptionAt("S8", media_raw_audio_format::B_AUDIO_CHAR, 1); + format->AddOptionAt("S16", media_raw_audio_format::B_AUDIO_SHORT, 2); + format->AddOptionAt("S32", media_raw_audio_format::B_AUDIO_INT, 3); + format->AddOptionAt("F32", media_raw_audio_format::B_AUDIO_FLOAT, 4); + + return format; +} + + +class MainWindow: public BWindow +{ + public: + MainWindow(); + + void MessageReceived(BMessage* what); + + private: + BTextControl* fInputRate; + BTextControl* fOutputRate; + BCheckBox* fInterpolate; + + BTextControl* fSignalVolume; + BTextControl* fSignalFrequency; + + WaveView* fWaveView; +}; + + +MainWindow::MainWindow() + : + BWindow(BRect(100, 100, 400, 400), "Mixer test", B_DOCUMENT_WINDOW, + B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS) +{ + SetLayout(new BGroupLayout(B_VERTICAL)); + + BBox* inputGroup = new BBox("Input", 0, B_FANCY_BORDER); + inputGroup->SetLabel("Input"); + + BGroupView* inputs = new BGroupView(B_VERTICAL); + inputs->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING, + B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING); + inputGroup->AddChild(inputs); + + fInputRate = new BTextControl("rate", "Sampling rate:", "256", + new BMessage(kMsgParametersChanged)); + inputs->AddChild(fInputRate); +#if 0 + inputs->AddChild(makeFormatMenu()); +#endif + + fSignalVolume = new BTextControl("vol", "Volume:", "127", + new BMessage(kMsgParametersChanged)); + inputs->AddChild(fSignalVolume); + fSignalFrequency = new BTextControl("freq", "Signal freq:", "256", + new BMessage(kMsgParametersChanged)); + inputs->AddChild(fSignalFrequency); + + BBox* outputGroup = new BBox("Output", 0, B_FANCY_BORDER); + outputGroup->SetLabel("Output"); + + BGroupView* outputs = new BGroupView(B_VERTICAL); + outputs->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING, + B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING, B_USE_DEFAULT_SPACING); + outputGroup->AddChild(outputs); + + fOutputRate = new BTextControl("rate", "Sampling rate:", "256", + new BMessage(kMsgParametersChanged)); + outputs->AddChild(fOutputRate); +#if 0 + outputs->AddChild(makeFormatMenu()); + BTextControl* volume = new BTextControl("vol", "Gain:", "1", NULL); + outputs->AddChild(volume); +#endif + + fInterpolate = new BCheckBox("interp", "Interpolate", + new BMessage(kMsgParametersChanged)); + outputs->AddChild(fInterpolate); + + BGroupView* header = new BGroupView(B_HORIZONTAL); + AddChild(header); + header->GroupLayout()->SetInsets(B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING, + B_USE_WINDOW_SPACING, B_USE_WINDOW_SPACING); + header->AddChild(inputGroup); + header->AddChild(outputGroup); + + AddChild(fWaveView = new WaveView()); +} + + +void +MainWindow::MessageReceived(BMessage* message) +{ + switch (message->what) { + case kMsgParametersChanged: + { + int freq = atoi(fSignalFrequency->Text()); + fWaveView->waves[0].Resize(freq); + + int irate = atoi(fInputRate->Text()); + fWaveView->waves[1].Resize(irate); + + int orate = atoi(fOutputRate->Text()); + fWaveView->waves[2].Resize(orate); + + int vol = atoi(fSignalVolume->Text()); + + fWaveView->waves[0].step = 1; + fWaveView->waves[1].step = (float)freq / irate; + fWaveView->waves[2].step = (float)freq / orate; + fWaveView->zoom = vol; + + for (int i = 0; i < freq; i++) { + fWaveView->waves[0].SetValue(i, sinf(i * 2 * M_PI / freq)); + } + + for (int i = 0; i < irate; i++) { + fWaveView->waves[1].SetValue(i, + fWaveView->waves[0].ValueAt(i * freq / irate)); + } + + // FIXME handle gain + if (fInterpolate->Value() == B_CONTROL_ON) { + Interpolate sampler(media_raw_audio_format::B_AUDIO_FLOAT, + media_raw_audio_format::B_AUDIO_FLOAT); + + sampler.Resample(fWaveView->waves[1].Raw(), sizeof(float), irate, + fWaveView->waves[2].Raw(), sizeof(float), orate, 1); + } else { + Resampler sampler(media_raw_audio_format::B_AUDIO_FLOAT, + media_raw_audio_format::B_AUDIO_FLOAT); + + sampler.Resample(fWaveView->waves[1].Raw(), sizeof(float), irate, + fWaveView->waves[2].Raw(), sizeof(float), orate, 1); + } + + fWaveView->Invalidate(); + return; + } + } + + BWindow::MessageReceived(message); +} + + +int main(int argc, char** argv) +{ + BApplication app("application/x-vnd.Haiku-MixerToy"); + (new MainWindow())->Show(); + app.Run(); +}