CSL  6.0
CSL_TestComponent.cpp
Go to the documentation of this file.
1 /*
2  ==============================================================================
3 
4  This is an automatically generated GUI class created by the Projucer!
5 
6  Be careful when adding custom code to these files, as only the code within
7  the "//[xyz]" and "//[/xyz]" sections will be retained when the file is loaded
8  and re-saved.
9 
10  Created with Projucer version: 6.0.0
11 
12  ------------------------------------------------------------------------------
13 
14  The Projucer is part of the JUCE library.
15  Copyright (c) 2017 - ROLI Ltd.
16 
17  ==============================================================================
18 */
19 
20 //[Headers] You can add your own extra header files here...
21 
22 //[/Headers]
23 
24 #include "CSL_TestComponent.h"
25 
26 
27 //[MiscUserDefs] You can add your own user definitions and misc code here...
28 
29 using namespace csl;
30 
31 // the CSL test suite lists
32 
33 // These are structs that are declared in the individual CSL test suite files
34 // struct testStruct { char * name; void (* fcn)(); };
35 // Each test suite has a list of its functions
36 
37 extern testStruct oscTestList[];
38 extern testStruct srcTestList[];
39 extern testStruct envTestList[];
40 extern testStruct effTestList[];
41 extern testStruct panTestList[];
42 #ifdef USE_JMIDI
43 extern testStruct ctrlTestList[];
44 #endif
45 extern testStruct audioTestList[];
46 
53 #ifdef USE_JMIDI
54  ctrlTestList,
55 #endif
56  audioTestList
57 };
58 
59 const char * allTestNames[] = {
60  "Oscillator Tests",
61  "Source Tests",
62  "Envelope Tests",
63  "Effect Tests",
64  "Panner Tests",
65 #ifdef USE_JMIDI
66  "Control Tests",
67 #endif
68  "Audio Tests"
69 };
70 
71 const char * allTestFiles[] = {
72  "Test_Oscillators.cpp",
73  "Test_Sources.cpp",
74  "Test_Envelopes.cpp",
75  "Test_Effects.cpp",
76  "Test_Panners.cpp",
77 #ifdef USE_JMIDI
78  "Test_Control.cpp",
79 #endif
80  "Test_Audio.cpp"
81 };
82 
83 testStruct * gTestList; // global menu
84 
85 // Pretty-print the test menu
86 
87 void dumpTestList() {
88  printf("\nMenu List\n");
89 #ifdef USE_JMIDI
90  unsigned numSuites = 7;
91 #else
92  unsigned numSuites = 6;
93 #endif
94  for (unsigned i = 0; i < numSuites; i++) {
95  gTestList = allTests[i];
96  const char * testName = allTestNames[i];
97  printf("\n%s - %s\n", testName, allTestFiles[i]);
98 // printf("</ul>\n<li>%s</li>\n<ul>", testName);
99  for (unsigned j = 0; gTestList[j].name != NULL; j++) {
100  printf("%24s %s\n", gTestList[j].name, gTestList[j].comment);
101 // printf("<li>%s -- %s</li>\n", gTestList[j].name, gTestList[j].comment);
102  }
103  }
104  printf("\n\n");
105 }
106 
107 // The main() function reads argv[1] as the suite selector (from the above list, 1-based)
108 // and argv[2] as the test within the suite, e.g., use "2 10" to select the 10th test in the
109 // srcTestList suite ("Vector IFFT" -- found at the bottom of Test_Sources.cpp).
110 // This is useful for debugging; set up the GUI to run the test you're working on.
111 
112 // Globals are here
113 
114 extern IO * theIO; // global IO object accessed by other threads
115 juce::Label* gCPULabel; // CPU % label...
116 juce::AudioDeviceManager * gAudioDeviceManager; // global JUCE audio device mgr
117 unsigned argCnt; // globals for argc/v from cmd-line
118 const char **argVals;
119 
120 #define WRITE_TO_FILE // support file recording
121 #ifdef WRITE_TO_FILE
122  Buffer * gFileBuffer = 0; // global buffer for file cache
123  int gSampIndex = 0; // write index into out buffer
124 #endif
125 
126 //
127 // LThread run function spawns/loops its CThread and sleeps interruptably
128 //
129 
130 void LThread::run() {
131  while (1) { // endless loop
132  if (thr->isThreadRunning()) // sleep some
133  if (csl::sleepMsec(250)) // interruptable sleep, check for failure
134  goto turn_off;
135  if (this->threadShouldExit()) // check flag
136  goto turn_off;
137  if ( ! thr->isThreadRunning()) { // if off
138  if (loop)
139  thr->startThread(); // restart if looping
140  else {
141 turn_off: if (CGestalt::stopNow()) { // if a timer was interrupted
142  CGestalt::clearStopNow(); // clear the global flag
143  thr->signalThreadShouldExit();
144  }
145  comp->playing = false;
146  const juce::MessageManagerLock mmLock; // create a lock to call the GUI thread here
147  if (comp->isTimerRunning())
148  comp->stopTimer(); // nasty to do this from here, but it freezes the GUI
149 // if (comp->playButton)
150 // comp->playButton->setButtonText(T("Play"));
151  if (comp->recrding)
152  comp->recordOnOff();
153  return;
154  }
155  }
156  }
157 }
158 
159 //[/MiscUserDefs]
160 
161 //==============================================================================
163 {
164  //[Constructor_pre] You can add your own custom stuff here..
165  //[/Constructor_pre]
166 
167  playButton.reset (new TextButton ("playNote"));
168  addAndMakeVisible (playButton.get());
169  playButton->setButtonText (TRANS("Play/Stop"));
170  playButton->addListener (this);
171 
172  quitButton.reset (new TextButton ("quitAction"));
173  addAndMakeVisible (quitButton.get());
174  quitButton->setButtonText (TRANS("Quit"));
175  quitButton->addListener (this);
176 
177  testCombo.reset (new ComboBox ("test to run"));
178  addAndMakeVisible (testCombo.get());
179  testCombo->setEditableText (false);
180  testCombo->setJustificationType (Justification::centredLeft);
181  testCombo->setTextWhenNothingSelected (String());
182  testCombo->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
183  testCombo->addListener (this);
184 
185  oscilloscopeL.reset (new AudioWaveformDisplay());
186  addAndMakeVisible (oscilloscopeL.get());
187  oscilloscopeL->setName ("new component");
188 
189  label.reset (new Label ("CSL test",
190  TRANS("CSL 6.0 Demos - select from the menus at the lower-left")));
191  addAndMakeVisible (label.get());
192  label->setFont (Font (Font::getDefaultSerifFontName(), 24.00f, Font::plain).withTypefaceStyle ("Bold"));
193  label->setJustificationType (Justification::centred);
194  label->setEditable (false, false, false);
195  label->setColour (Label::textColourId, Colour (0xfffffc00));
196  label->setColour (TextEditor::textColourId, Colours::black);
197  label->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
198 
199  prefsButton.reset (new TextButton ("new button"));
200  addAndMakeVisible (prefsButton.get());
201  prefsButton->setButtonText (TRANS("Audio Prefs"));
202  prefsButton->addListener (this);
203 
204  prefsButton->setBounds (8, 8, 144, 32);
205 
206  cpuLabel.reset (new Label ("new label",
207  TRANS("0.0%")));
208  addAndMakeVisible (cpuLabel.get());
209  cpuLabel->setFont (Font (Font::getDefaultSansSerifFontName(), 15.00f, Font::plain).withTypefaceStyle ("Bold"));
210  cpuLabel->setJustificationType (Justification::centredRight);
211  cpuLabel->setEditable (false, false, false);
212  cpuLabel->setColour (TextEditor::textColourId, Colours::black);
213  cpuLabel->setColour (TextEditor::backgroundColourId, Colour (0x00000000));
214 
215  oscilloscopeR.reset (new AudioWaveformDisplay());
216  addAndMakeVisible (oscilloscopeR.get());
217  oscilloscopeR->setName ("new component");
218 
219  VUMeterL.reset (new VUMeter());
220  addAndMakeVisible (VUMeterL.get());
221  VUMeterL->setName ("new component");
222 
223  VUMeterR.reset (new VUMeter());
224  addAndMakeVisible (VUMeterR.get());
225  VUMeterR->setName ("new component");
226 
227  scaleSlider.reset (new Slider ("new slider"));
228  addAndMakeVisible (scaleSlider.get());
229  scaleSlider->setRange (0, 1, 0);
230  scaleSlider->setSliderStyle (Slider::LinearHorizontal);
231  scaleSlider->setTextBoxStyle (Slider::NoTextBox, true, 80, 20);
232  scaleSlider->addListener (this);
233 
234  amplitudeSlider.reset (new Slider ("new slider"));
235  addAndMakeVisible (amplitudeSlider.get());
236  amplitudeSlider->setRange (-5, 5, 0);
237  amplitudeSlider->setSliderStyle (Slider::LinearVertical);
238  amplitudeSlider->setTextBoxStyle (Slider::NoTextBox, true, 8, 20);
239  amplitudeSlider->addListener (this);
240 
241  loopButton.reset (new ToggleButton ("new toggle button"));
242  addAndMakeVisible (loopButton.get());
243  loopButton->setButtonText (TRANS("Loop"));
244  loopButton->addListener (this);
245 
246  familyCombo.reset (new ComboBox ("test family"));
247  addAndMakeVisible (familyCombo.get());
248  familyCombo->setEditableText (false);
249  familyCombo->setJustificationType (Justification::centredLeft);
250  familyCombo->setTextWhenNothingSelected (String());
251  familyCombo->setTextWhenNoChoicesAvailable (TRANS("(no choices)"));
252  familyCombo->addItem (TRANS("Oscillators"), 1);
253  familyCombo->addItem (TRANS("Sources"), 2);
254  familyCombo->addItem (TRANS("Envelopes"), 3);
255  familyCombo->addItem (TRANS("Effects"), 4);
256  familyCombo->addItem (TRANS("Panners"), 5);
257  familyCombo->addItem (TRANS("Controls"), 6);
258  familyCombo->addListener (this);
259 
260  recordButton.reset (new ToggleButton ("new toggle button"));
261  addAndMakeVisible (recordButton.get());
262  recordButton->setButtonText (TRANS("Record"));
263  recordButton->addListener (this);
264 
265 
266  //[UserPreSize]
267  oscilloscopeL->initialise(0, 20, 2, true); // channel, rate, window, zeroX
268  oscilloscopeR->initialise(1, 20, 2, true);
269  //[/UserPreSize]
270 
271  setSize (1000, 700);
272 
273 
274  //[Constructor] You can add your own custom stuff here..
275 
276 ////////////////////////////// Here we go! //////////////////////////////////////////
277  // CSL Code starts here
278 // dumpTestList(); // print out the demo/test menu
279 
280  // initiali[zs]e the device manager so it picks a default device to use.
281  const juce::String error (mAudioDeviceManager.initialise (0, /* no input */
282  2, /* stereo output */
283  0, /* no XML defaults */
284  true /* select default device */));
285  if (error.isNotEmpty())
286  juce::AlertWindow::showMessageBox (juce::AlertWindow::WarningIcon,
287  "CSL Demo",
288  "Couldn't open an output device!\n\n" + error);
289  // get the audio device
290  juce::AudioIODevice* audioIO = mAudioDeviceManager.getCurrentAudioDevice();
291 
292 #ifdef READ_IO_PROPS // overwrite the system frame rate and block size from the
293  // selected hardware interface at startup time
294  unsigned sRate = (unsigned) audioIO->getCurrentSampleRate();
295  unsigned bufSize = audioIO->getCurrentBufferSizeSamples();
296  theIO = new csl::IO(sRate, bufSize, -1, -1, // still use the default # IO channels
299 
300 #else // reset the HW frame rate & block size to the CSL definition
301  juce::AudioDeviceManager::AudioDeviceSetup setup;
302  mAudioDeviceManager.getAudioDeviceSetup(setup);
303  setup.bufferSize = CGestalt::blockSize();
304  setup.sampleRate = CGestalt::frameRate();
305  mAudioDeviceManager.setAudioDeviceSetup(setup,true);
306  // set up CSL IO
307  theIO = new csl::IO(CGestalt::frameRate(),
309  -1, -1, // use default I/O devices
312 #endif
313  theIO->start(); // start IO and register callback
314  mAudioDeviceManager.addAudioCallback(this);
315 
316  gCPULabel = cpuLabel.get(); // component settings
317  gAudioDeviceManager = & mAudioDeviceManager;
318  playThread = 0;
319  loopThread = 0;
320  loop = false;
321  playing = false;
322  displayMode = true;
323  recrding = false;
324 
325  amplitudeSlider->setValue(0.8); // GUI settings
326  scaleSlider->setValue(0.1);
327  oscilloscopeL->start();
328  oscilloscopeR->start();
329  VUMeterL->setChannel(0);
330  VUMeterR->setChannel(1);
331  loopButton->setToggleState (false, false);
332 // spectrogam->setVisible(false);
333 
334  int whichSuite = 1; // set default suite/test
335  int whichTest = 1;
336  // try to read init file
337  string initMsg(CGestalt::initFileText('T'));
338  if (initMsg.size() > 0) {
339  sscanf(initMsg.c_str(), "%d %d", & whichSuite, & whichTest);
340  printf("Select suite %d, test %d\n", whichSuite, whichTest);
341  }
342 // if (argCnt > 1) // cmd-line args select test suite and test
343 // whichSuite = atoi(argVals[1]);
344 // if (argCnt > 2)
345 // whichTest = atoi(argVals[2]);
346 // if (argCnt > 1)
347 // printf("Select suite %d, test %d\n", whichSuite, whichTest);
348  // combo menu selections
349  familyCombo->setSelectedId(whichSuite, true);
350  this->setComboLabels(whichSuite - 1);
351  testCombo->setSelectedId(whichTest, true);
352 
353  //[/Constructor]
354 }
355 
357 {
358  //[Destructor_pre]. You can add your own custom destruction code here..
359 
360  if (playing) // CSL shut-down
361  this->startStop();
362  playing = false;
363  mAudioDeviceManager.removeAudioCallback(this);
364  if (gFileBuffer) {
365  gFileBuffer->freeBuffers();
366  delete gFileBuffer;
367  }
368 
369  //[/Destructor_pre]
370 
371  playButton = nullptr;
372  quitButton = nullptr;
373  testCombo = nullptr;
374  oscilloscopeL = nullptr;
375  label = nullptr;
376  prefsButton = nullptr;
377  cpuLabel = nullptr;
378  oscilloscopeR = nullptr;
379  VUMeterL = nullptr;
380  VUMeterR = nullptr;
381  scaleSlider = nullptr;
382  amplitudeSlider = nullptr;
383  loopButton = nullptr;
384  familyCombo = nullptr;
385  recordButton = nullptr;
386 
387 
388  //[Destructor]. You can add your own custom destruction code here..
389  //[/Destructor]
390 }
391 
392 //==============================================================================
393 void CSLComponent::paint (Graphics& g)
394 {
395  //[UserPrePaint] Add your own custom painting code here..
396  //[/UserPrePaint]
397 
398  g.fillAll (Colours::grey);
399 
400  //[UserPaint] Add your own custom painting code here..
401  //[/UserPaint]
402 }
403 
405 {
406  //[UserPreResize] Add your own custom resize code here..
407  //[/UserPreResize]
408 
409  playButton->setBounds (380, getHeight() - 39, 136, 32);
410  quitButton->setBounds (getWidth() - 8 - 176, 8, 176, 32);
411  testCombo->setBounds (184, getHeight() - 35, 176, 24);
412  oscilloscopeL->setBounds (44, 48, getWidth() - 52, proportionOfHeight (0.4200f));
413  label->setBounds (436 - (558 / 2), 10, 558, 28);
414  cpuLabel->setBounds (getWidth() - 64, getHeight() - 35, 56, 24);
415  oscilloscopeR->setBounds (44, proportionOfHeight (0.5000f), getWidth() - 52, proportionOfHeight (0.4200f));
416  VUMeterL->setBounds (25, 48, 15, roundToInt (proportionOfHeight (0.4200f) * 1.0000f));
417  VUMeterR->setBounds (24, proportionOfHeight (0.5000f), 15, roundToInt (proportionOfHeight (0.4200f) * 1.0000f));
418  scaleSlider->setBounds (36, getHeight() - 60, getWidth() - 36, 24);
419  amplitudeSlider->setBounds (0, 42, 20, proportionOfHeight (0.8700f));
420  loopButton->setBounds (380 + 136 - -24, getHeight() - 11 - 24, 64, 24);
421  familyCombo->setBounds (48, getHeight() - 35, 128, 24);
422  recordButton->setBounds ((getWidth() - 8 - 176) + -12 - 72, 37 - 24, 72, 24);
423  //[UserResized] Add your own custom resize handling here..
424  //[/UserResized]
425 }
426 
427 void CSLComponent::buttonClicked (Button* buttonThatWasClicked)
428 {
429  //[UserbuttonClicked_Pre]
430  //[/UserbuttonClicked_Pre]
431 
432  if (buttonThatWasClicked == playButton.get())
433  {
434  //[UserButtonCode_playButton] -- add your button handler code here..
435 
436  this->startStop();
437 
438  //[/UserButtonCode_playButton]
439  }
440  else if (buttonThatWasClicked == quitButton.get())
441  {
442  //[UserButtonCode_quitButton] -- add your button handler code here..
443 
444  if (playing)
445  this->startStop();
446  juce::JUCEApplication::quit();
447 
448  //[/UserButtonCode_quitButton]
449  }
450  else if (buttonThatWasClicked == prefsButton.get())
451  {
452  //[UserButtonCode_prefsButton] -- add your button handler code here..
453 
454  // Create an AudioDeviceSelectorComponent which contains the audio choice widgets...
455 // if (displayMode) {
456  oscilloscopeL->stop(); // stop scope display during dialog
457  oscilloscopeR->stop();
458 // } else {
459 // spectrogam->stop();
460 // }
461 // AudioDeviceSelectorComponent (AudioDeviceManager& deviceManager,
462 // const int minAudioInputChannels,
463 // const int maxAudioInputChannels,
464 // const int minAudioOutputChannels,
465 // const int maxAudioOutputChannels,
466 // const bool showMidiInputOptions,
467 // const bool showMidiOutputSelector,
468 // const bool showChannelsAsStereoPairs,
469 // const bool hideAdvancedOptionsWithButton);
470 
471  juce::AudioDeviceSelectorComponent audioSettingsComp (mAudioDeviceManager,
474  true, true,
475  false, false);
476  // ...and show it in a DialogWindow...
477  audioSettingsComp.setSize (500, 400);
478  juce::DialogWindow::showModalDialog ("Audio Settings",
479  &audioSettingsComp,
480  this,
481  juce::Colours::azure,
482  true);
483 // if (displayMode) {
484  oscilloscopeL->start(); // stop scope display during dialog
485  oscilloscopeR->start();
486 // } else {
487 // spectrogam->start();
488 // }
489 
490  //[/UserButtonCode_prefsButton]
491  }
492  else if (buttonThatWasClicked == loopButton.get())
493  {
494  //[UserButtonCode_loopButton] -- add your button handler code here..
495 
496  if (loop) {
497  if (loopThread) {
498  loopThread->stopThread(100);
499  delete loopThread;
500  loopThread = 0;
501  }
502  }
503  loop = ! loop;
504 
505  //[/UserButtonCode_loopButton]
506  }
507  else if (buttonThatWasClicked == recordButton.get())
508  {
509  //[UserButtonCode_recordButton] -- add your button handler code here..
510 
511  bool wasRec = recrding;
512  recordOnOff();
513  if (wasRec)
514  recrding = false;
515 
516  //[/UserButtonCode_recordButton]
517  }
518 
519  //[UserbuttonClicked_Post]
520  //[/UserbuttonClicked_Post]
521 }
522 
523 void CSLComponent::comboBoxChanged (ComboBox* comboBoxThatHasChanged)
524 {
525  //[UsercomboBoxChanged_Pre]
526  //[/UsercomboBoxChanged_Pre]
527 
528  if (comboBoxThatHasChanged == testCombo.get())
529  {
530  //[UserComboBoxCode_testCombo] -- add your combo box handling code here..
531 
532 // printf("\tSelect test %d\n", testCombo->getSelectedId());
533 
534  //[/UserComboBoxCode_testCombo]
535  }
536  else if (comboBoxThatHasChanged == familyCombo.get())
537  {
538  //[UserComboBoxCode_familyCombo] -- add your combo box handling code here..
539 
540 // printf("\tSelect suite %d\n", familyCombo->getSelectedId());
541  this->setComboLabels(familyCombo->getSelectedId() - 1);
542 
543  //[/UserComboBoxCode_familyCombo]
544  }
545 
546  //[UsercomboBoxChanged_Post]
547  //[/UsercomboBoxChanged_Post]
548 }
549 
550 void CSLComponent::sliderValueChanged (Slider* sliderThatWasMoved)
551 {
552  //[UsersliderValueChanged_Pre]
553  //[/UsersliderValueChanged_Pre]
554 
555  if (sliderThatWasMoved == scaleSlider.get())
556  {
557  //[UserSliderCode_scaleSlider] -- add your slider handling code here..
558 
559  unsigned stepValue = (unsigned) (scaleSlider->getValue() * 10.0) + 1;
560  oscilloscopeL->setSamplesToAverage(stepValue);
561  oscilloscopeR->setSamplesToAverage(stepValue);
562 
563  //[/UserSliderCode_scaleSlider]
564  }
565  else if (sliderThatWasMoved == amplitudeSlider.get())
566  {
567  //[UserSliderCode_amplitudeSlider] -- add your slider handling code here..
568 
569  amplValue = pow(2.0, amplitudeSlider->getValue());
570 
571  //[/UserSliderCode_amplitudeSlider]
572  }
573 
574  //[UsersliderValueChanged_Post]
575  //[/UsersliderValueChanged_Post]
576 }
577 
578 
579 
580 //[MiscUserCode] You can add your own definitions of your custom methods or any other code here...
581 
582 //
583 /////////////// CSL/JUCE Audio callback method ///////////////////
584 //
585 
586 void CSLComponent::audioDeviceIOCallback (const float** inputChannelData,
587  int totalNumInputChannels,
588  float** outputChannelData,
589  int totalNumOutputChannels,
590  int numSamples) {
591  // put silence in the output buffers
592  for (unsigned i = 0; i < totalNumOutputChannels; i++)
593  memset(outputChannelData[i], 0, numSamples * sizeof(float));
594 
595  if ( ! playing) // if off
596  return;
597  if (CGestalt::stopNow()) // if being interrupted
598  return;
599  // set up CSL buffer object
600  if (theIO->mGraph) {
601  outBuffer.setSize(totalNumOutputChannels, numSamples);
602  outBuffer.mAreBuffersAllocated = true;
603 
604  // copy JUCE data ptrs into outBuffer
605  for (unsigned i = 0; i < totalNumOutputChannels; i++)
606  outBuffer.setBuffer(i, outputChannelData[i]);
607 
608  try { //////
609  // Tell the IO to call its graph
610  //////
611  theIO->pullInput(outBuffer);
612  outBuffer.mIsPopulated = true;
613  outBuffer.mAreBuffersZero = false;
614 
615  } catch (csl::CException e) {
616  logMsg(kLogError, "Error running CSL: graph: %s\n", e.what());
617  }
618  if (amplValue != 1.0f) { // scale by volume slider
619  // channel loop
620  for (unsigned i = 0; i < totalNumOutputChannels; i++) {
621  float * sampPtr = outputChannelData[i];
622  // frame loop
623  for (unsigned j = 0; j < numSamples; j++)
624  *sampPtr++ *= amplValue;
625  }}
626  // pass the audio callback on to the waveform display components
627  oscilloscopeL->audioDeviceIOCallback (inputChannelData, totalNumInputChannels,
628  outputChannelData, totalNumOutputChannels, numSamples);
629  oscilloscopeR->audioDeviceIOCallback (inputChannelData, totalNumInputChannels,
630  outputChannelData, totalNumOutputChannels, numSamples);
631  VUMeterL->audioDeviceIOCallback (inputChannelData, 0,
632  outputChannelData, totalNumOutputChannels, numSamples);
633  VUMeterR->audioDeviceIOCallback (inputChannelData, 0,
634  outputChannelData, totalNumOutputChannels, numSamples);
635 // spectrogam->audioDeviceIOCallback (inputChannelData, totalNumInputChannels,
636 // outputChannelData, totalNumOutputChannels, numSamples);
637 
638  if (recrding) { // cache to (stereo) record buffer
639  if (gSampIndex >= SAMPS_TO_WRITE)
640  return;
641  if ( ! gFileBuffer)
642  return;
643  // get cache ptrs & copy outbuf
644  csl::sample * sPtr = gFileBuffer->buffer(0) + gSampIndex;
645  memcpy(sPtr, outputChannelData[0], (numSamples * sizeof(csl::sample)));
646  sPtr = gFileBuffer->buffer(1) + gSampIndex;
647  memcpy(sPtr, outputChannelData[1], (numSamples * sizeof(csl::sample)));
648  // update ptrs
649  gSampIndex += numSamples;
650  gFileBuffer->mNumFrames = gSampIndex;
651  }
652  } // if mGraph
653 }
654 
655 // Handle file output in record mode; creates a remp file named "dataFolder(), OUT_SFILE_NAME"
656 // such as /Users/stp/Code/CSL/CSL_Data/02_csl_out.aiff
657 // The template is XX_csl_out.aiff, could be like CSL_TakeXX.aiff.
658 // Increments the field XX in the name template with integers, wrapping at 100.
659 //
660 
662  if (recrding) { // stop recording and write output file
663  if (gFileBuffer->mNumFrames == 0)
664  return;
665  string outName = CGestalt::sndFileName();
666  // write to snd file
667  logMsg("Write %5.3f sec (%d ksamp) to file \"%s\"\n",
668  ((float) gSampIndex / CGestalt::frameRate()), gSampIndex / 1000, outName.c_str());
669  SoundFile * ioFile = new SoundFile(outName);
670  ioFile->openForWrite(kSoundFileFormatAIFF, 2);
671  ioFile->writeBuffer(*gFileBuffer); // snd file write of record buffer
672  ioFile->close();
673  delete ioFile;
674 
675  } else { // start recording
676  if ( ! gFileBuffer) { // allocate buffer first time
677  gFileBuffer = new Buffer(2, SAMPS_TO_WRITE + CGestalt::maxBufferFrames());
678  gFileBuffer->allocateBuffers();
679  }
680  recrding = true; // set flag checked in audioDeviceIOCallback
681  }
682  gSampIndex = 0; // reset write ptr
683  gFileBuffer->mNumFrames = gSampIndex;
684 }
685 
686 // Audio device support
687 
688 void CSLComponent::audioDeviceAboutToStart (juce::AudioIODevice* device) {
689  oscilloscopeL->audioDeviceAboutToStart (device);
690  oscilloscopeR->audioDeviceAboutToStart (device);
691 // spectrogam->audioDeviceAboutToStart (device);
692 // csl::CGestalt::setBlockSize(numSamplesPerBlock);
693 }
694 
696 // oscilloscope->audioDeviceStopped();
697 }
698 
699 // Set up the combo box from the individual test suite methods
700 
701 void CSLComponent::setComboLabels(unsigned which) {
702  testCombo->clear();
703  gTestList = allTests[which];
704  for (unsigned i = 0; gTestList[i].name != NULL; i++) {
705 // printf("\tAdd \"%s\"\n", gTestList[i].name);
706  testCombo->addItem(juce::String(gTestList[i].name), i + 1);
707  }
708  testCombo->setSelectedId(1);
709 }
710 
711 // create the component -- called from main()
712 
713 juce::Component* createCSLComponent() {
714  return new CSLComponent();
715 }
716 
717 // timer call
718 
720  const juce::MessageManagerLock mmLock; // create the lock so we can call the GUI thread from this thread
721  char msg[10]; // print the CPU usage
722  sprintf(msg, "%5.2f%%", (gAudioDeviceManager->getCpuUsage() * 100.0));
723  juce::String msgS(msg);
724  gCPULabel->setText(msgS, juce::sendNotification);
725 }
726 
727 // start/stop
728 
730  if ( ! playing) { // if not playing, start!
731  int which = testCombo->getSelectedId();
732  if (which == 0)
733  return;
734  char initmsg[16]; // store test to file
735  sprintf(initmsg, "%d %d", familyCombo->getSelectedId(), testCombo->getSelectedId());
736  CGestalt::storeToInitFile('T', string(initmsg));
737 
738  playing = true;
739  CGestalt::clearStopNow(); // clear flag
740  // create a threadfcn that plays CSL
741  ThreadFunc fcn = (void * (*)(void *)) gTestList[which - 1].fcn;
742 
743  playThread = new GThread(fcn); // thread to call the CSL test function
744  playThread->startThread();
745  loopThread = new LThread(playThread, this, loop); // thread to wait and/or loop it
746  loopThread->startThread();
747 // playButton->setButtonText (T("Stop"));
748  this->startTimer(1000); // 1-sec timer
749  } else { // if playing
750  playing = false;
751  theIO->clearRoot();
752  this->stopTimer();
753  CGestalt::setStopNow(); // set flag to clear timers
754  if (recrding)
755  recordOnOff();
756  sleepMsec(100);
757  if (loop)
758  loopThread->stopThread(1000);
759  if (playThread->isThreadRunning())
760  playThread->stopThread(1000); // try to kill
761  delete playThread;
762  playThread = 0;
763 // playButton->setButtonText (T("Play"));
764  CGestalt::clearStopNow(); // clear flag
765  }
766 }
767 
768 //[/MiscUserCode]
769 
770 
771 //==============================================================================
772 #if 0
773 /* -- Projucer information section --
774 
775  This is where the Projucer stores the metadata that describe this GUI layout, so
776  make changes in here at your peril!
777 
778 BEGIN_JUCER_METADATA
779 
780 <JUCER_COMPONENT documentType="Component" className="CSLComponent" componentName=""
781  parentClasses="public Component, public AudioIODeviceCallback, public Timer"
782  constructorParams="" variableInitialisers="" snapPixels="8" snapActive="1"
783  snapShown="1" overlayOpacity="0.330" fixedSize="1" initialWidth="1000"
784  initialHeight="700">
785  <BACKGROUND backgroundColour="ff808080"/>
786  <TEXTBUTTON name="playNote" id="ed1811e776eea99b" memberName="playButton"
787  virtualName="" explicitFocusOrder="0" pos="380 39R 136 32" buttonText="Play/Stop"
788  connectedEdges="0" needsCallback="1" radioGroupId="0"/>
789  <TEXTBUTTON name="quitAction" id="dbaf2871fd41de83" memberName="quitButton"
790  virtualName="" explicitFocusOrder="0" pos="8Rr 8 176 32" buttonText="Quit"
791  connectedEdges="0" needsCallback="1" radioGroupId="0"/>
792  <COMBOBOX name="test to run" id="bd1a5c541fbc8bc7" memberName="testCombo"
793  virtualName="" explicitFocusOrder="0" pos="184 35R 176 24" editable="0"
794  layout="33" items="" textWhenNonSelected="" textWhenNoItems="(no choices)"/>
795  <GENERICCOMPONENT name="new component" id="d64c351a292a43a4" memberName="oscilloscopeL"
796  virtualName="" explicitFocusOrder="0" pos="44 48 52M 42%" class="AudioWaveformDisplay"
797  params=""/>
798  <LABEL name="CSL test" id="a9876f115ab3c22e" memberName="label" virtualName=""
799  explicitFocusOrder="0" pos="436c 10 558 28" textCol="fffffc00"
800  edTextCol="ff000000" edBkgCol="0" labelText="CSL 6.0 Demos - select from the menus at the lower-left"
801  editableSingleClick="0" editableDoubleClick="0" focusDiscardsChanges="0"
802  fontname="Default serif font" fontsize="24.0" kerning="0.0" bold="1"
803  italic="0" justification="36" typefaceStyle="Bold"/>
804  <TEXTBUTTON name="new button" id="beeb15a1537fd4f6" memberName="prefsButton"
805  virtualName="" explicitFocusOrder="0" pos="8 8 144 32" buttonText="Audio Prefs"
806  connectedEdges="0" needsCallback="1" radioGroupId="0"/>
807  <LABEL name="new label" id="87d3c5b55ea75f76" memberName="cpuLabel"
808  virtualName="" explicitFocusOrder="0" pos="64R 35R 56 24" edTextCol="ff000000"
809  edBkgCol="0" labelText="0.0%" editableSingleClick="0" editableDoubleClick="0"
810  focusDiscardsChanges="0" fontname="Default sans-serif font" fontsize="15.0"
811  kerning="0.0" bold="1" italic="0" justification="34" typefaceStyle="Bold"/>
812  <GENERICCOMPONENT name="new component" id="4aa0f216430fecde" memberName="oscilloscopeR"
813  virtualName="" explicitFocusOrder="0" pos="44 50% 52M 42%" class="AudioWaveformDisplay"
814  params=""/>
815  <GENERICCOMPONENT name="new component" id="28308fd8ae783890" memberName="VUMeterL"
816  virtualName="" explicitFocusOrder="0" pos="25 48 15 100%" posRelativeH="d64c351a292a43a4"
817  class="VUMeter" params=""/>
818  <GENERICCOMPONENT name="new component" id="643b07b4b6cf41d" memberName="VUMeterR"
819  virtualName="" explicitFocusOrder="0" pos="24 50% 15 100%" posRelativeH="4aa0f216430fecde"
820  class="VUMeter" params=""/>
821  <SLIDER name="new slider" id="c62ea84a7afde2e3" memberName="scaleSlider"
822  virtualName="" explicitFocusOrder="0" pos="36 60R 36M 24" min="0.0"
823  max="1.0" int="0.0" style="LinearHorizontal" textBoxPos="NoTextBox"
824  textBoxEditable="0" textBoxWidth="80" textBoxHeight="20" skewFactor="1.0"
825  needsCallback="1"/>
826  <SLIDER name="new slider" id="78c6bd39da739ba6" memberName="amplitudeSlider"
827  virtualName="" explicitFocusOrder="0" pos="0 42 20 87%" min="-5.0"
828  max="5.0" int="0.0" style="LinearVertical" textBoxPos="NoTextBox"
829  textBoxEditable="0" textBoxWidth="8" textBoxHeight="20" skewFactor="1.0"
830  needsCallback="1"/>
831  <TOGGLEBUTTON name="new toggle button" id="2322f603f1796f48" memberName="loopButton"
832  virtualName="" explicitFocusOrder="0" pos="-24R 11Rr 64 24" posRelativeX="ed1811e776eea99b"
833  buttonText="Loop" connectedEdges="0" needsCallback="1" radioGroupId="0"
834  state="0"/>
835  <COMBOBOX name="test family" id="55af3a98f2faf643" memberName="familyCombo"
836  virtualName="" explicitFocusOrder="0" pos="48 35R 128 24" editable="0"
837  layout="33" items="Oscillators&#10;Sources&#10;Envelopes&#10;Effects&#10;Panners&#10;Controls"
838  textWhenNonSelected="" textWhenNoItems="(no choices)"/>
839  <TOGGLEBUTTON name="new toggle button" id="82a5a3f16d517231" memberName="recordButton"
840  virtualName="" explicitFocusOrder="0" pos="-12r 37r 72 24" posRelativeX="dbaf2871fd41de83"
841  buttonText="Record" connectedEdges="0" needsCallback="1" radioGroupId="0"
842  state="0"/>
843 </JUCER_COMPONENT>
844 
845 END_JUCER_METADATA
846 */
847 #endif
848 
849 
850 //[EndFile] You can add extra defines here...
851 //[/EndFile]
852 
void logMsg(const char *format,...)
These are the public logging messages.
Definition: CGestalt.cpp:292
static std::string initFileText(char key)
read/write the init file (typ. ~/.cslrc)
Definition: CGestalt.cpp:126
testStruct * gTestList
testStruct * allTests[]
#define kSoundFileFormatAIFF
Definition: SoundFile.h:60
#define SAMPS_TO_WRITE
record 30 seconds by default
Definition: CSL_Types.h:125
void *(* ThreadFunc)(void *)
This is the CSL_AbstComponent JUCE wrapper for the CSL demos.
unsigned mNumFrames
num frames used in each buffer
Definition: CSL_Core.h:113
bool sleepMsec(float dur)
Definition: CGestalt.cpp:372
AdditiveInstrument.h – Sum-of-sines synthesis instrument class.
Definition: Accessor.h:17
const char * allTestNames[]
void pullInput(Buffer &outBuffer, SampleBuffer out=0)
get a buffer from the CSL graph
Definition: CSL_Core.cpp:1425
static std::string sndFileName()
pick a new sound file name to use based on OUT_SFILE_NAME
Definition: CGestalt.cpp:186
static void storeToInitFile(char key, std::string data)
Definition: CGestalt.cpp:145
void comboBoxChanged(ComboBox *comboBoxThatHasChanged) override
IO * theIO
static unsigned numOutChannels()
default number of output channels
Definition: CGestalt.cpp:59
static bool stopNow()
flag to stop threads and timers
Definition: CGestalt.cpp:64
static unsigned maxBufferFrames()
the max num frames that can be requested
Definition: CGestalt.cpp:54
testStruct srcTestList[]
testStruct effTestList[]
virtual SampleBuffer buffer(unsigned bufNum)
convenience accessors for sample buffers
Definition: CSL_Core.cpp:66
const char * allTestFiles[]
GThread takes a CSL test function and runs it.
juce::AudioDeviceManager * gAudioDeviceManager
juce::Component * createCSLComponent()
const char * name
Definition: CSL_Types.h:266
void freeBuffers()
fcn to free them
Definition: CSL_Core.cpp:141
static void clearStopNow()
Definition: CGestalt.cpp:101
struct used for the JUCE pop-up menu of tests (see the test files)
Definition: CSL_Types.h:265
UnitGenerator * mGraph
the root of my client DSP graph, often a mixer or panner
Definition: CSL_Core.h:777
const char * what()
static unsigned blockSize()
the default block size
Definition: CGestalt.cpp:57
virtual void start()
Definition: CSL_Core.h:761
testStruct envTestList[]
int gSampIndex
~CSLComponent() override
float sample
(could be changed to int, or double)
Definition: CSL_Types.h:191
IO – the abstract I/O scheduling class; subclasses interface to specific I/O APIs.
Definition: CSL_Core.h:752
VoidFcnPtrN * fcn
Definition: CSL_Types.h:267
static unsigned frameRate()
default frame rate
Definition: CGestalt.cpp:51
void resized() override
void audioDeviceAboutToStart(juce::AudioIODevice *device)
static unsigned numInChannels()
default number of input channels
Definition: CGestalt.cpp:58
juce::Label * gCPULabel
Buffer * gFileBuffer
void setComboLabels(unsigned which)
void buttonClicked(Button *buttonThatWasClicked) override
Buffer – the multi-channel sample buffer class (passed around between generators and IO guys)...
Definition: CSL_Core.h:106
const char ** argVals
void clearRoot()
Definition: CSL_Core.cpp:1410
unsigned argCnt
void dumpTestList()
void paint(Graphics &g) override
testStruct oscTestList[]
void allocateBuffers()
fcn to malloc storage buffers
Definition: CSL_Core.cpp:122
testStruct panTestList[]
static void setStopNow()
Definition: CGestalt.cpp:100
void error(int num, const char *m, const char *path)
Definition: OSC_support.cpp:70
void sliderValueChanged(Slider *sliderThatWasMoved) override
testStruct audioTestList[]
Definition: Test_Audio.cpp:115
Base class of CSL exceptions (written upper-case). Has a string message.
void audioDeviceIOCallback(const float **inputChannelData, int totalNumInputChannels, float **outputChannelData, int totalNumOutputChannels, int numSamples)