Various changes

main
Thor 1 year ago
parent b933f936f8
commit d7b13aad99
  1. 15
      CMakeLists.txt
  2. 1
      include/synth/channel.h
  3. 35
      include/synth/dsp/filter.h
  4. 33
      include/synth/dsp/util.h
  5. 41
      include/synth/frame.h
  6. 40
      include/synth/globals.h
  7. 1
      include/synth/synth.h
  8. 2
      include/synth/voice.h
  9. 52
      src/genluts.cpp
  10. 1
      src/synth/channel.cpp
  11. 18
      src/synth/dsp/centlut.cpp
  12. 14
      src/synth/dsp/filterlut.cpp
  13. 18
      src/synth/dsp/notelut.cpp
  14. 8
      src/synth/synth.cpp
  15. 9
      src/synth/voicemanager.cpp
  16. 63
      src/synthapp.cpp
  17. 2
      xctrace-command.txt

@ -3,6 +3,13 @@ project(synth)
set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD 20)
set(BUILD_SHARED_LIBS OFF) set(BUILD_SHARED_LIBS OFF)
if(MSVC)
set(CMAKE_CXX_FLAGS_DEBUG "/W4 /DEBUG:FASTLINK /fp:fast")
set(CMAKE_CXX_FLAGS_RELEASE "/W4 /O2 /fp:fast /DNDEBUG")
else()
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -g -ffast-math")
set(CMAKE_CXX_FLAGS_RELEASE "-Wall -Ofast -DNDEBUG")
endif()
if(WIN32) if(WIN32)
option(PA_USE_ASIO "" ON) option(PA_USE_ASIO "" ON)
@ -26,6 +33,8 @@ add_executable(main
src/synth/channel.cpp src/synth/channel.cpp
src/synth/preset.cpp src/synth/preset.cpp
src/synth/voice.cpp src/synth/voice.cpp
src/synth/dsp/notelut.cpp
src/synth/dsp/centlut.cpp
src/synth/dsp/oscillator.cpp src/synth/dsp/oscillator.cpp
src/synth/dsp/filter.cpp src/synth/dsp/filter.cpp
src/synth/dsp/filterlut.cpp src/synth/dsp/filterlut.cpp
@ -35,12 +44,6 @@ target_include_directories(main PRIVATE include)
add_executable(genluts src/genluts.cpp) add_executable(genluts src/genluts.cpp)
target_include_directories(genluts PRIVATE include) target_include_directories(genluts PRIVATE include)
if(MSVC)
target_compile_options(main PRIVATE /fp:fast)
else()
target_compile_options(main PRIVATE -ffast-math)
endif()
#target_compile_options(main PRIVATE -fsanitize=thread) #target_compile_options(main PRIVATE -fsanitize=thread)
#target_link_options(main PRIVATE -fsanitize=thread) #target_link_options(main PRIVATE -fsanitize=thread)

@ -8,6 +8,7 @@
#include "voicemanager.h" #include "voicemanager.h"
#include "voice.h" #include "voice.h"
#include "preset.h" #include "preset.h"
#include "frame.h"
class Channel { class Channel {
public: public:

@ -5,27 +5,34 @@
#include <cmath> #include <cmath>
#include <cfloat> #include <cfloat>
#include <iostream>
#include "../globals.h"
#include "util.h" #include "util.h"
#define FILTER_K_BASE 6.214608098422192 #define FILTER_K_BASE 6.214608098422192
#define KLUT_SIZE 64 #ifdef USE_LUTS
extern float klut[KLUT_SIZE];
#define K_LUT_SIZE 64
inline float freqToK(float x) {
float intPart; extern float kLUT[K_LUT_SIZE];
float fracPart = modf(x * (KLUT_SIZE - 1), &intPart);
int index = (int) intPart; inline float freqToK(float x) {
if(fracPart < FLT_EPSILON) { float intPart, fracPart = modf(x * (K_LUT_SIZE - 1), &intPart);
return klut[index]; int index = (int) intPart;
} else { return fracPart < FLT_EPSILON ? kLUT[index] : (1 - fracPart) * kLUT[index] + fracPart * kLUT[index + 1];
return (1 - fracPart) * klut[index] + fracPart * klut[index + 1];
} }
return klut[(int) roundf((KLUT_SIZE - 1) * x)];
}
inline float noteToK(float note) { #else
inline float freqToK(float x) {
return tan(M_PI_4 * 0.002 * exp(x * FILTER_K_BASE));
}
#endif
inline float noteToFltFreq(float note) {
return ((note - 69) / 12.0) / (FILTER_K_BASE * M_LOG2E); return ((note - 69) / 12.0) / (FILTER_K_BASE * M_LOG2E);
} }

@ -2,19 +2,36 @@
#define __UTIL_H__ #define __UTIL_H__
#include <cmath> #include <cmath>
#include <cfloat>
#include "../globals.h"
#define PIx2 (2 * M_PI) #define PIx2 (2 * M_PI)
inline float clamp(float x, float a, float b) { #ifdef USE_LUTS
return fminf(b, fmaxf(a, x));
}
inline float dBToGain(float dB) { #define NOTE_LUT_SIZE 128
return pow(10, dB / 20.0); #define CENT_LUT_SIZE 128
}
extern float noteLUT[NOTE_LUT_SIZE];
extern float centLUT[CENT_LUT_SIZE];
inline float noteToFreq(float note) {
float intPart, fracPart = modf(note, &intPart);
int index = (int) intPart;
return fracPart < FLT_EPSILON ? noteLUT[index] : noteLUT[index] * centLUT[(int) (fracPart * 127.0)];
}
#else
inline float noteToFreq(float note) {
return 440 * pow(2, (note - 69) / 12.0);
}
inline float noteToFreq(float note) { #endif
return 440 * pow(2, (note - 69) / 12.0);
inline float clamp(float x, float a, float b) {
return fminf(b, fmaxf(a, x));
} }
inline float triangle(float phase) { inline float triangle(float phase) {

@ -0,0 +1,41 @@
#ifndef __FRAME_H__
#define __FRAME_H__
struct frame {
float left;
float right;
inline frame operator+(const frame& rhs) {
return {
.left = left + rhs.left,
.right = right + rhs.right
};
}
inline frame operator+=(const frame& rhs) {
this->left += rhs.left;
this->right += rhs.right;
return *this;
}
inline frame operator*(float rhs) {
return {
.left = left * rhs,
.right = right * rhs
};
}
inline frame operator+=(float rhs) {
this->left += rhs;
this->right += rhs;
return *this;
}
inline frame operator*=(float rhs) {
this->left *= rhs;
this->right *= rhs;
return *this;
}
};
#endif

@ -1,44 +1,8 @@
#ifndef __GLOBALS_H__ #ifndef __GLOBALS_H__
#define __GLOBALS_H__ #define __GLOBALS_H__
#define SAMPLE_RATE 48000 #define SAMPLE_RATE 44100
struct frame { //#define USE_LUTS
float left;
float right;
inline frame operator+(const frame& rhs) {
return {
.left = left + rhs.left,
.right = right + rhs.right
};
}
inline frame operator+=(const frame& rhs) {
this->left += rhs.left;
this->right += rhs.right;
return *this;
}
inline frame operator*(float rhs) {
return {
.left = left * rhs,
.right = right * rhs
};
}
inline frame operator+=(float rhs) {
this->left += rhs;
this->right += rhs;
return *this;
}
inline frame operator*=(float rhs) {
this->left *= rhs;
this->right *= rhs;
return *this;
}
};
#endif #endif

@ -3,6 +3,7 @@
#include "voicemanager.h" #include "voicemanager.h"
#include "channel.h" #include "channel.h"
#include "frame.h"
class Synth { class Synth {
public: public:

@ -53,7 +53,7 @@ public:
float out = 0; float out = 0;
out += (1 - settings->oscMix) * osc1.tick(osc1PhaseStep); out += (1 - settings->oscMix) * osc1.tick(osc1PhaseStep);
out += settings->oscMix * osc2.tick(osc2PhaseStep); out += settings->oscMix * osc2.tick(osc2PhaseStep);
const float keyTrackVal = settings->keyTrack * noteToK(note); const float keyTrackVal = settings->keyTrack * noteToFltFreq(note);
out = filter.tick(out, settings->modEnvFltGain * adsrMod.tick() + keyTrackVal + fltFreqAdd); out = filter.tick(out, settings->modEnvFltGain * adsrMod.tick() + keyTrackVal + fltFreqAdd);
out *= adsrAmp.tick(); out *= adsrAmp.tick();
return out; return out;

@ -1,30 +1,46 @@
#include <stdio.h> #include <cstdio>
#include <math.h> #include <cmath>
#include "synth/dsp/filter.h" #define USE_LUTS
int main(int argc, char** argv) {
FILE* f;
float klut[KLUT_SIZE]; #include "synth/dsp/filter.h"
for(int i = 0; i < KLUT_SIZE; ++i) { #include "synth/dsp/util.h"
klut[i] = tan(M_PI_4 * 0.002 * exp(i / (KLUT_SIZE - 1.0) * FILTER_K_BASE));
}
f = fopen("src/synth/dsp/filterlut.cpp", "w"); void dumpLUT(const char * filename, const char * identifier, float *lut, size_t size) {
fputs("float klut[] = {\n", f); FILE * f = fopen(filename, "w");
for(int i = 0; i < KLUT_SIZE; ++i) { fprintf(f, "float %s[] = {\n", identifier);
if(i % 16 == 0) { for(int i = 0; i < size; ++i) {
if(i % 8 == 0) {
fputs(" ", f); fputs(" ", f);
} }
fprintf(f, "%.7f", klut[i]); fprintf(f, "%13.7f", lut[i]);
if(i < KLUT_SIZE - 1) { if(i < size - 1) {
fputs(", ", f); fputs(", ", f);
} }
if(i % 16 == 15) { if(i % 8 == 7) {
putc('\n', f); putc('\n', f);
} }
} }
fputs("};\n", f); fputs("};\n", f);
fclose(f); fclose(f);
}
int main(int argc, char** argv) {
float kLUT[K_LUT_SIZE];
for(int i = 0; i < K_LUT_SIZE; ++i) {
kLUT[i] = tan(M_PI_4 * 0.002 * exp(i / (K_LUT_SIZE - 1.0) * FILTER_K_BASE));
}
dumpLUT("src/synth/dsp/filterlut.cpp", "kLUT", kLUT, K_LUT_SIZE);
float noteLUT[NOTE_LUT_SIZE];
for(int i = 0; i < NOTE_LUT_SIZE; ++i) {
noteLUT[i] = 440 * pow(2, (i - 69) / 12.0);
}
dumpLUT("src/synth/dsp/notelut.cpp", "noteLUT", noteLUT, NOTE_LUT_SIZE);
float centLUT[CENT_LUT_SIZE];
for(int i = 0; i < CENT_LUT_SIZE; ++i) {
centLUT[i] = pow(2, (float) i / ((CENT_LUT_SIZE - 1) * 12.0));
}
dumpLUT("src/synth/dsp/centlut.cpp", "centLUT", centLUT, CENT_LUT_SIZE);
} }

@ -93,7 +93,6 @@ void Channel::control(int code, int value) {
case CC_FLT_Q: // Timbre / Harmonic Content (Standard MIDI) case CC_FLT_Q: // Timbre / Harmonic Content (Standard MIDI)
settings.filter.res = value / 31.75; settings.filter.res = value / 31.75;
std::cout << "Q=" << settings.filter.res << std::endl;
break; break;
case CC_AMP_REL: // Release Time (Standard MIDI) case CC_AMP_REL: // Release Time (Standard MIDI)

@ -0,0 +1,18 @@
float centLUT[] = {
1.0000000, 1.0004549, 1.0009100, 1.0013654, 1.0018209, 1.0022767, 1.0027326, 1.0031888,
1.0036452, 1.0041018, 1.0045586, 1.0050156, 1.0054728, 1.0059302, 1.0063878, 1.0068456,
1.0073037, 1.0077620, 1.0082204, 1.0086790, 1.0091379, 1.0095969, 1.0100563, 1.0105158,
1.0109755, 1.0114354, 1.0118955, 1.0123559, 1.0128164, 1.0132772, 1.0137382, 1.0141994,
1.0146607, 1.0151223, 1.0155841, 1.0160462, 1.0165083, 1.0169708, 1.0174334, 1.0178963,
1.0183593, 1.0188227, 1.0192862, 1.0197498, 1.0202137, 1.0206778, 1.0211421, 1.0216067,
1.0220715, 1.0225364, 1.0230016, 1.0234669, 1.0239326, 1.0243984, 1.0248644, 1.0253307,
1.0257971, 1.0262637, 1.0267307, 1.0271977, 1.0276650, 1.0281326, 1.0286002, 1.0290682,
1.0295364, 1.0300047, 1.0304732, 1.0309421, 1.0314111, 1.0318803, 1.0323497, 1.0328194,
1.0332892, 1.0337592, 1.0342295, 1.0347000, 1.0351708, 1.0356417, 1.0361128, 1.0365841,
1.0370557, 1.0375276, 1.0379995, 1.0384717, 1.0389441, 1.0394168, 1.0398897, 1.0403627,
1.0408360, 1.0413095, 1.0417832, 1.0422572, 1.0427313, 1.0432056, 1.0436803, 1.0441550,
1.0446301, 1.0451053, 1.0455807, 1.0460564, 1.0465323, 1.0470084, 1.0474846, 1.0479612,
1.0484380, 1.0489149, 1.0493921, 1.0498694, 1.0503471, 1.0508249, 1.0513029, 1.0517812,
1.0522597, 1.0527384, 1.0532173, 1.0536964, 1.0541759, 1.0546554, 1.0551351, 1.0556152,
1.0560954, 1.0565759, 1.0570565, 1.0575374, 1.0580184, 1.0584998, 1.0589813, 1.0594631
};

@ -1,6 +1,10 @@
float klut[] = { float kLUT[] = {
0.0015708, 0.0017336, 0.0019134, 0.0021118, 0.0023307, 0.0025723, 0.0028390, 0.0031333, 0.0034582, 0.0038167, 0.0042124, 0.0046491, 0.0051311, 0.0056631, 0.0062502, 0.0068982, 0.0015708, 0.0017336, 0.0019134, 0.0021118, 0.0023307, 0.0025723, 0.0028390, 0.0031333,
0.0076134, 0.0084028, 0.0092740, 0.0102355, 0.0112968, 0.0124681, 0.0137608, 0.0151877, 0.0167625, 0.0185007, 0.0204193, 0.0225369, 0.0248743, 0.0274544, 0.0303024, 0.0334462, 0.0034582, 0.0038167, 0.0042124, 0.0046491, 0.0051311, 0.0056631, 0.0062502, 0.0068982,
0.0369167, 0.0407480, 0.0449779, 0.0496483, 0.0548053, 0.0605004, 0.0667905, 0.0737388, 0.0814158, 0.0898997, 0.0992782, 0.1096492, 0.1211226, 0.1338222, 0.1478880, 0.1634790, 0.0076134, 0.0084028, 0.0092740, 0.0102355, 0.0112968, 0.0124681, 0.0137608, 0.0151877,
0.1807770, 0.1999912, 0.2213640, 0.2451794, 0.2717728, 0.3015462, 0.3349871, 0.3726965, 0.4154281, 0.4641461, 0.5201120, 0.5850177, 0.6611994, 0.7519926, 0.8623521, 1.0000000 0.0167625, 0.0185007, 0.0204193, 0.0225369, 0.0248743, 0.0274544, 0.0303024, 0.0334462,
0.0369167, 0.0407480, 0.0449779, 0.0496483, 0.0548053, 0.0605004, 0.0667905, 0.0737388,
0.0814158, 0.0898997, 0.0992782, 0.1096492, 0.1211226, 0.1338222, 0.1478880, 0.1634790,
0.1807770, 0.1999912, 0.2213640, 0.2451794, 0.2717728, 0.3015462, 0.3349871, 0.3726965,
0.4154281, 0.4641461, 0.5201120, 0.5850177, 0.6611994, 0.7519926, 0.8623521, 1.0000000
}; };

@ -0,0 +1,18 @@
float noteLUT[] = {
8.1757994, 8.6619568, 9.1770239, 9.7227182, 10.3008614, 10.9133825, 11.5623255, 12.2498569,
12.9782715, 13.7500000, 14.5676174, 15.4338531, 16.3515987, 17.3239136, 18.3540478, 19.4454365,
20.6017227, 21.8267651, 23.1246510, 24.4997139, 25.9565430, 27.5000000, 29.1352348, 30.8677063,
32.7031975, 34.6478271, 36.7080956, 38.8908730, 41.2034454, 43.6535301, 46.2493019, 48.9994278,
51.9130859, 55.0000000, 58.2704697, 61.7354126, 65.4063950, 69.2956543, 73.4161911, 77.7817459,
82.4068909, 87.3070602, 92.4986038, 97.9988556, 103.8261719, 110.0000000, 116.5409393, 123.4708252,
130.8127899, 138.5913086, 146.8323822, 155.5634918, 164.8137817, 174.6141205, 184.9972076, 195.9977112,
207.6523438, 220.0000000, 233.0818787, 246.9416504, 261.6255798, 277.1826172, 293.6647644, 311.1269836,
329.6275635, 349.2282410, 369.9944153, 391.9954224, 415.3046875, 440.0000000, 466.1637573, 493.8833008,
523.2511597, 554.3652344, 587.3295288, 622.2539673, 659.2551270, 698.4564819, 739.9888306, 783.9908447,
830.6093750, 880.0000000, 932.3275146, 987.7666016, 1046.5023193, 1108.7304688, 1174.6590576, 1244.5079346,
1318.5102539, 1396.9129639, 1479.9776611, 1567.9816895, 1661.2187500, 1760.0000000, 1864.6550293, 1975.5332031,
2093.0046387, 2217.4609375, 2349.3181152, 2489.0158691, 2637.0205078, 2793.8259277, 2959.9553223, 3135.9633789,
3322.4375000, 3520.0000000, 3729.3100586, 3951.0664062, 4186.0092773, 4434.9218750, 4698.6362305, 4978.0317383,
5274.0410156, 5587.6518555, 5919.9106445, 6271.9267578, 6644.8750000, 7040.0000000, 7458.6201172, 7902.1328125,
8372.0185547, 8869.8437500, 9397.2724609, 9956.0634766, 10548.0820312, 11175.3037109, 11839.8212891, 12543.8535156
};

@ -1,18 +1,18 @@
#include <iostream> #include <cstdio>
#include "synth/synth.h" #include "synth/synth.h"
void Synth::noteOn(int ch, int note, int vel) { void Synth::noteOn(int ch, int note, int vel) {
channels[ch].noteOn(note, vel); channels[ch].noteOn(note, vel);
std::cout << "Note On: ch=" << ch << " note=" << note << " vel=" << vel << std::endl; printf("Note On: ch=%d note=%d vel=%d\n", ch, note, vel);
} }
void Synth::noteOff(int ch, int note) { void Synth::noteOff(int ch, int note) {
channels[ch].noteOff(note); channels[ch].noteOff(note);
std::cout << "Note Off: ch=" << ch << " note=" << note << std::endl; printf("Note Off: ch=%d note=%d\n", ch, note);
} }
void Synth::control(int ch, int cc, int val) { void Synth::control(int ch, int cc, int val) {
channels[ch].control(cc, val); channels[ch].control(cc, val);
std::cout << "Controller: ch=" << ch << " cc=" << cc << " val=" << val << std::endl; printf("Controller: ch=%d cc=%d val=%d\n", ch, cc, val);
} }

@ -1,4 +1,4 @@
#include <iostream> #include <cstdio>
#include "synth/voicemanager.h" #include "synth/voicemanager.h"
@ -20,10 +20,11 @@ Voice * VoiceManager::get(channel_t channel) {
voiceData.serial = serial++; voiceData.serial = serial++;
voiceData.voice.reset(); voiceData.voice.reset();
putchar('\n');
for(VoiceData& vd : voices) { for(VoiceData& vd : voices) {
std::cout << "channel=" << vd.channel << " serial=" << vd.serial << " idle=" << vd.voice.isIdle() << " note=" << vd.voice.note << std::endl; printf("channel=%d serial=%d idle=%d note=%d\n", vd.channel, vd.serial, vd.voice.isIdle(), vd.voice.note);
} }
std::cout << std::endl; putchar('\n');
return &voiceData.voice; return &voiceData.voice;
} }
@ -38,4 +39,4 @@ Voice** VoiceManager::getChannelVoices(channel_t channel) {
} }
*voice = NULL; *voice = NULL;
return result; return result;
} }

@ -1,6 +1,6 @@
#include <cstdlib> #include <cstdlib>
#include <cstdio>
#include <cmath> #include <cmath>
#include <iostream>
#include "synth/globals.h" #include "synth/globals.h"
@ -10,6 +10,7 @@
using namespace std; using namespace std;
// PortAudio callback for audio I/O // PortAudio callback for audio I/O
bool firstPACallback = true;
static int paCallback( static int paCallback(
const void *inputBuffer, const void *inputBuffer,
void *outputBuffer, void *outputBuffer,
@ -20,6 +21,11 @@ static int paCallback(
SynthApp *app = (SynthApp*) userData; SynthApp *app = (SynthApp*) userData;
if(firstPACallback) {
printf("Buffer size is %ld frames\n", framesPerBuffer);
firstPACallback = false;
}
PmEvent events[16]; PmEvent events[16];
int numEvents = Pm_Read(app->pmStream, events, 16); int numEvents = Pm_Read(app->pmStream, events, 16);
for(int i = 0; i < numEvents; ++i) { for(int i = 0; i < numEvents; ++i) {
@ -40,13 +46,6 @@ static int paCallback(
int val = Pm_MessageData2(msg); int val = Pm_MessageData2(msg);
app->synth.control(ch, cc, val); app->synth.control(ch, cc, val);
} }
/*
cout << "MIDI:";
for(int j = 0; j < 24; j += 8) {
cout << " " << hex << ((msg >> j) & 0xFF);
}
cout << endl;
*/
} }
float *out = (float*) outputBuffer; float *out = (float*) outputBuffer;
@ -90,19 +89,22 @@ bool SynthApp::OnInit() {
} }
int pmDeviceCount = Pm_CountDevices(); int pmDeviceCount = Pm_CountDevices();
cout << "Select MIDI input device:" << endl; putchar('\n');
printf("Select MIDI input device:\n\n");
for(int i = 0; i < pmDeviceCount; ++i) { for(int i = 0; i < pmDeviceCount; ++i) {
const PmDeviceInfo* deviceInfo = Pm_GetDeviceInfo(i); const PmDeviceInfo* deviceInfo = Pm_GetDeviceInfo(i);
if(!deviceInfo->input) { if(!deviceInfo->input) {
continue; continue;
} }
cout << i << ". " << deviceInfo->name << endl; printf("%d. %s\n", i, deviceInfo->name);
} }
putchar('\n');
int pmDeviceIndex; int pmDeviceIndex;
for(;;) { // loop for input until valid choice is made for(;;) { // loop for input until valid choice is made
string input; printf("Number: ");
getline(cin, input); char input[4];
//string input = "1"; fgets(input, 4, stdin);
//const char* input = "1";
try { try {
pmDeviceIndex = stoi(input); pmDeviceIndex = stoi(input);
if( pmDeviceIndex >= 0 && if( pmDeviceIndex >= 0 &&
@ -111,23 +113,27 @@ bool SynthApp::OnInit() {
break; break;
} }
} catch(...) { } // stoi() throws an exeption for invalid integers } catch(...) { } // stoi() throws an exeption for invalid integers
cout << "Invalid selection" << endl; printf("Invalid selection\n");
} }
putchar('\n');
PaHostApiIndex paDeviceCount = Pa_GetDeviceCount(); PaHostApiIndex paDeviceCount = Pa_GetDeviceCount();
cout << "Select audio output device:" << endl; printf("Select audio output device:\n\n");
for(int i = 0; i < paDeviceCount; ++i) { for(int i = 0; i < paDeviceCount; ++i) {
const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(i); const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(i);
if(deviceInfo->maxOutputChannels < 2) { if(deviceInfo->maxOutputChannels < 2) {
continue; continue;
} }
cout << i << ". " << deviceInfo->name << " (" << Pa_GetHostApiInfo(deviceInfo->hostApi)->name << ")" << endl; printf("%d. %s (%s)\n", i, deviceInfo->name, Pa_GetHostApiInfo(deviceInfo->hostApi)->name);
} }
putchar('\n');
PaHostApiIndex paDeviceIndex; PaHostApiIndex paDeviceIndex;
for(;;) { // loop for input until valid choice is made for(;;) { // loop for input until valid choice is made
string input; printf("Number: ");
getline(cin, input); char input[4];
//string input = "4"; fgets(input, 4, stdin);
//const char* input = "5";
try { try {
paDeviceIndex = stoi(input); paDeviceIndex = stoi(input);
if( paDeviceIndex >= 0 && if( paDeviceIndex >= 0 &&
@ -136,11 +142,11 @@ bool SynthApp::OnInit() {
break; break;
} }
} catch(...) { } // stoi() throws an exeption for invalid integers } catch(...) { } // stoi() throws an exeption for invalid integers
cout << "Invalid selection" << endl; printf("Invalid selection\n");
} }
// Open MIDI input // Open MIDI input
PmError pmError = Pm_OpenInput( pmErr = Pm_OpenInput(
&pmStream, &pmStream,
pmDeviceIndex, pmDeviceIndex,
NULL, NULL,
@ -151,18 +157,25 @@ bool SynthApp::OnInit() {
handlePMError(pmErr); handlePMError(pmErr);
} }
const PaDeviceInfo* deviceInfo = Pa_GetDeviceInfo(paDeviceIndex);
putchar('\n');
printf("Default sample rate is %.0f Hz\n", deviceInfo->defaultSampleRate);
printf("Default low input latency is %.0f samples\n", deviceInfo->defaultSampleRate * deviceInfo->defaultLowOutputLatency);
putchar('\n');
// Configure/start audio output stream // Configure/start audio output stream
PaStreamParameters paStreamParams; PaStreamParameters paStreamParams;
paStreamParams.device = paDeviceIndex; paStreamParams.device = paDeviceIndex;
paStreamParams.channelCount = 2; paStreamParams.channelCount = 2;
paStreamParams.sampleFormat = paFloat32; paStreamParams.sampleFormat = paFloat32;
paStreamParams.suggestedLatency = 512.0 / SAMPLE_RATE; paStreamParams.suggestedLatency = deviceInfo->defaultLowOutputLatency;
paStreamParams.hostApiSpecificStreamInfo = NULL; paStreamParams.hostApiSpecificStreamInfo = NULL;
paErr = Pa_OpenStream( paErr = Pa_OpenStream(
&paStream, &paStream,
NULL, // no input channels NULL, // no input channels
&paStreamParams, // stereo output &paStreamParams, // stereo output
SAMPLE_RATE, deviceInfo->defaultSampleRate,
0, // frames per buffer 0, // frames per buffer
paNoFlag, paNoFlag,
paCallback, paCallback,
@ -176,7 +189,7 @@ bool SynthApp::OnInit() {
} }
const PaStreamInfo *paStreamInfo = Pa_GetStreamInfo(paStream); const PaStreamInfo *paStreamInfo = Pa_GetStreamInfo(paStream);
cout << "Latency: " << round(1000 * paStreamInfo->outputLatency) << " ms" << endl; printf("Reported latency is %d frames\n", (int) round(SAMPLE_RATE * paStreamInfo->outputLatency));
wxFrame *frame = new SynthFrame(); wxFrame *frame = new SynthFrame();
frame->Show(true); frame->Show(true);
@ -197,7 +210,7 @@ int SynthApp::OnExit() {
handlePMError(pmErr); handlePMError(pmErr);
} }
Pa_Terminate(); Pa_Terminate();
cout << "Terminating" << endl; printf("\nTerminating\n");
return 0; return 0;
} }

@ -1 +1 @@
xctrace record --template 'Time Profiler' --target-stdin - --target-stdout - --launch ./build/main xctrace record --template 'Time Profiler' --launch ./build/main
Loading…
Cancel
Save