1 /* Copyright 2014 Haiku, Inc.
2 * Distributed under the terms of the MIT license.
9 #include <Application.h>
12 #include <GroupLayout.h>
13 #include <GroupView.h>
14 #include <MediaDefs.h>
15 #include <OptionPopUp.h>
16 #include <TextControl.h>
19 #include <Interpolate.h>
20 #include <Resampler.h>
23 static const int32 kMsgParametersChanged
= 'pmch';
35 { Resize(1); step
= 1; }
36 float ValueAt(int index
) { return fData
[index
% fSize
]; }
37 void SetValue(int pos
, float val
) { fData
[pos
] = val
; }
38 void Resize(int newSize
) {
41 fData
= (float*)realloc(fData
, newSize
* sizeof(float));
44 int Size() { return fSize
; }
45 void* Raw() { return fData
; }
57 class WaveView
: public BView
62 void Draw(BRect update
);
64 Wave waves
[3]; // reference, input, and output
71 BView("wave", B_WILL_DRAW
)
73 SetExplicitMinSize(BSize(512, 256));
78 WaveView::Draw(BRect update
)
82 for (float i
= update
.left
; i
<= update
.right
; i
++) {
83 if (i
< waves
[0].Size())
84 SetHighColor(make_color(0, 0, 0, 255));
86 SetHighColor(make_color(180, 180, 180, 255));
87 BPoint
p(i
, waves
[0].ValueAt(i
) * zoom
);
94 // Skip the part outside the updat rect
95 while (w1pos
<= update
.left
) {
96 w1pos
+= waves
[1].step
;
100 while (w1pos
<= update
.right
) {
101 if (i
< waves
[1].Size())
102 SetHighColor(make_color(255, 0, 0, 255));
104 SetHighColor(make_color(255, 180, 180, 255));
105 BPoint
p1(w1pos
, INT16_MIN
);
106 BPoint
p2(w1pos
, waves
[1].ValueAt(i
) * zoom
);
109 w1pos
+= waves
[1].step
;
116 // Skip the part outside the updat rect
117 while (w1pos
<= update
.left
) {
118 w1pos
+= waves
[2].step
;
122 while (w1pos
<= update
.right
) {
123 if (i
< waves
[2].Size())
124 SetHighColor(make_color(0, 255, 0, 255));
126 SetHighColor(make_color(180, 255, 180, 255));
127 BPoint
p1(w1pos
, INT16_MAX
);
128 BPoint
p2(w1pos
, waves
[2].ValueAt(i
) * zoom
);
131 w1pos
+= waves
[2].step
;
141 static BOptionPopUp
* makeFormatMenu()
143 BOptionPopUp
* format
= new BOptionPopUp("fmt", "Sample format:", NULL
);
144 format
->AddOptionAt("U8", media_raw_audio_format::B_AUDIO_UCHAR
, 0);
145 format
->AddOptionAt("S8", media_raw_audio_format::B_AUDIO_CHAR
, 1);
146 format
->AddOptionAt("S16", media_raw_audio_format::B_AUDIO_SHORT
, 2);
147 format
->AddOptionAt("S32", media_raw_audio_format::B_AUDIO_INT
, 3);
148 format
->AddOptionAt("F32", media_raw_audio_format::B_AUDIO_FLOAT
, 4);
154 class MainWindow
: public BWindow
159 void MessageReceived(BMessage
* what
);
162 BTextControl
* fInputRate
;
163 BTextControl
* fOutputRate
;
164 BCheckBox
* fInterpolate
;
166 BTextControl
* fSignalVolume
;
167 BTextControl
* fSignalFrequency
;
173 MainWindow::MainWindow()
175 BWindow(BRect(100, 100, 400, 400), "Mixer test", B_DOCUMENT_WINDOW
,
176 B_QUIT_ON_WINDOW_CLOSE
| B_AUTO_UPDATE_SIZE_LIMITS
)
178 SetLayout(new BGroupLayout(B_VERTICAL
));
180 BBox
* inputGroup
= new BBox("Input", 0, B_FANCY_BORDER
);
181 inputGroup
->SetLabel("Input");
183 BGroupView
* inputs
= new BGroupView(B_VERTICAL
);
184 inputs
->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING
,
185 B_USE_DEFAULT_SPACING
, B_USE_DEFAULT_SPACING
, B_USE_DEFAULT_SPACING
);
186 inputGroup
->AddChild(inputs
);
188 fInputRate
= new BTextControl("rate", "Sampling rate:", "256",
189 new BMessage(kMsgParametersChanged
));
190 inputs
->AddChild(fInputRate
);
192 inputs
->AddChild(makeFormatMenu());
195 fSignalVolume
= new BTextControl("vol", "Volume:", "127",
196 new BMessage(kMsgParametersChanged
));
197 inputs
->AddChild(fSignalVolume
);
198 fSignalFrequency
= new BTextControl("freq", "Signal freq:", "256",
199 new BMessage(kMsgParametersChanged
));
200 inputs
->AddChild(fSignalFrequency
);
202 BBox
* outputGroup
= new BBox("Output", 0, B_FANCY_BORDER
);
203 outputGroup
->SetLabel("Output");
205 BGroupView
* outputs
= new BGroupView(B_VERTICAL
);
206 outputs
->GroupLayout()->SetInsets(B_USE_DEFAULT_SPACING
,
207 B_USE_DEFAULT_SPACING
, B_USE_DEFAULT_SPACING
, B_USE_DEFAULT_SPACING
);
208 outputGroup
->AddChild(outputs
);
210 fOutputRate
= new BTextControl("rate", "Sampling rate:", "256",
211 new BMessage(kMsgParametersChanged
));
212 outputs
->AddChild(fOutputRate
);
214 outputs
->AddChild(makeFormatMenu());
215 BTextControl
* volume
= new BTextControl("vol", "Gain:", "1", NULL
);
216 outputs
->AddChild(volume
);
219 fInterpolate
= new BCheckBox("interp", "Interpolate",
220 new BMessage(kMsgParametersChanged
));
221 outputs
->AddChild(fInterpolate
);
223 BGroupView
* header
= new BGroupView(B_HORIZONTAL
);
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
);
230 AddChild(fWaveView
= new WaveView());
235 MainWindow::MessageReceived(BMessage
* message
)
237 switch (message
->what
) {
238 case kMsgParametersChanged
:
240 int freq
= atoi(fSignalFrequency
->Text());
241 fWaveView
->waves
[0].Resize(freq
);
243 int irate
= atoi(fInputRate
->Text());
244 fWaveView
->waves
[1].Resize(irate
);
246 int orate
= atoi(fOutputRate
->Text());
247 fWaveView
->waves
[2].Resize(orate
);
249 int vol
= atoi(fSignalVolume
->Text());
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
;
256 for (int i
= 0; i
< freq
; i
++) {
257 fWaveView
->waves
[0].SetValue(i
, sinf(i
* 2 * M_PI
/ freq
));
260 for (int i
= 0; i
< irate
; i
++) {
261 fWaveView
->waves
[1].SetValue(i
,
262 fWaveView
->waves
[0].ValueAt(i
* freq
/ irate
));
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
);
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);
276 sampler
.Resample(fWaveView
->waves
[1].Raw(), sizeof(float), irate
,
277 fWaveView
->waves
[2].Raw(), sizeof(float), orate
, 1);
279 Resampler
sampler(media_raw_audio_format::B_AUDIO_FLOAT
,
280 media_raw_audio_format::B_AUDIO_FLOAT
);
282 sampler
.Resample(fWaveView
->waves
[1].Raw(), sizeof(float), irate
,
283 fWaveView
->waves
[2].Raw(), sizeof(float), orate
, 1);
286 fWaveView
->Invalidate();
291 BWindow::MessageReceived(message
);
295 int main(int argc
, char** argv
)
297 BApplication
app("application/x-vnd.Haiku-MixerToy");
298 (new MainWindow())->Show();