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