Skip to content

Commit 83ca579

Browse files
committed
working audio capture and SDL2 rendering hooray
1 parent f968739 commit 83ca579

File tree

2 files changed

+111
-41
lines changed

2 files changed

+111
-41
lines changed

src/projectM-sdl/SDLprojectM.xcodeproj/project.pbxproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@
144144
C345213C1BF02293001707D2 /* Project object */ = {
145145
isa = PBXProject;
146146
attributes = {
147-
LastUpgradeCheck = 0710;
147+
LastUpgradeCheck = 0830;
148148
ORGANIZATIONNAME = int80;
149149
TargetAttributes = {
150150
C34521431BF02293001707D2 = {
@@ -194,8 +194,10 @@
194194
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
195195
CLANG_WARN_EMPTY_BODY = YES;
196196
CLANG_WARN_ENUM_CONVERSION = YES;
197+
CLANG_WARN_INFINITE_RECURSION = YES;
197198
CLANG_WARN_INT_CONVERSION = YES;
198199
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
200+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
199201
CLANG_WARN_UNREACHABLE_CODE = YES;
200202
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
201203
CODE_SIGN_IDENTITY = "";
@@ -241,8 +243,10 @@
241243
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
242244
CLANG_WARN_EMPTY_BODY = YES;
243245
CLANG_WARN_ENUM_CONVERSION = YES;
246+
CLANG_WARN_INFINITE_RECURSION = YES;
244247
CLANG_WARN_INT_CONVERSION = YES;
245248
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
249+
CLANG_WARN_SUSPICIOUS_MOVE = YES;
246250
CLANG_WARN_UNREACHABLE_CODE = YES;
247251
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
248252
CODE_SIGN_IDENTITY = "";

src/projectM-sdl/projectM_SDL_main.cpp

Lines changed: 106 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -36,28 +36,94 @@ typedef struct {
3636
bool done;
3737
projectM::Settings settings;
3838
SDL_AudioDeviceID audioInputDevice;
39+
40+
// audio input device characteristics
41+
unsigned short audioChannelsCount;
42+
unsigned short audioSampleRate;
43+
unsigned short audioSampleCount;
44+
SDL_AudioFormat audioFormat;
45+
SDL_AudioDeviceID audioDeviceID;
46+
unsigned char *pcmBuffer; // pre-allocated buffer for audioInputCallback
3947
} projectMApp;
4048

41-
int selectAudioInput(projectMApp *app) {
42-
// audio input stuff here is very platform-specific
43-
// too bad the libsdl2 audio capture support doesn't exist
44-
45-
#ifdef __APPLE__
46-
// UInt32 audioInputIsAvailable;
47-
// UInt32 propertySize = sizeof (audioInputIsAvailable);
48-
49-
// AudioSessionGetProperty (
50-
// kAudioSessionProperty_AudioInputAvailable,
51-
// &propertySize,
52-
// &audioInputIsAvailable // A nonzero value on output means that
53-
// // audio input is available
54-
// );
49+
void audioInputCallbackF32(void *userdata, unsigned char *stream, int len) {
50+
// printf("LEN: %i\n", len);
51+
projectMApp *app = (projectMApp *) userdata;
52+
// stream is (i think) samples*channels floats (native byte order) of len BYTES
53+
app->pm->pcm()->addPCMfloat((float *)stream, len/sizeof(float));
54+
}
5555

56-
#endif
56+
void audioInputCallbackS16(void *userdata, unsigned char *stream, int len) {
57+
// printf("LEN: %i\n", len);
58+
projectMApp *app = (projectMApp *) userdata;
59+
short pcm16[2][512];
60+
61+
for (int i = 0; i < 512; i++) { //
62+
for (int j = 0; j < app->audioChannelsCount; j++) {
63+
pcm16[j][i] = stream[i+j];
64+
}
65+
}
66+
app->pm->pcm()->addPCM16(pcm16);
67+
}
68+
69+
70+
int openAudioInput(projectMApp *app) {
71+
// get audio input device
72+
int i, count = SDL_GetNumAudioDevices(true); // capture, please
73+
if (count == 0) {
74+
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "No audio capture devices found");
75+
SDL_Quit();
76+
}
77+
for (i = 0; i < count; i++) {
78+
SDL_Log("Found audio capture device %d: %s", i, SDL_GetAudioDeviceName(i, true));
79+
}
80+
81+
// params for audio input
82+
SDL_AudioSpec want, have;
83+
84+
// TODO: let user somehow select audio input device
85+
SDL_AudioDeviceID selectedAudioDevice = 0; // hardcoded to use first device for now :/
86+
87+
// requested format
88+
SDL_zero(want);
89+
want.freq = 48000;
90+
want.format = AUDIO_F32; // float
91+
want.channels = 2;
92+
want.samples = 512;
93+
want.callback = audioInputCallbackF32;
94+
want.userdata = app;
95+
96+
app->audioDeviceID = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(selectedAudioDevice, true), true, &want, &have, 0);
97+
98+
if (app->audioDeviceID == 0) {
99+
SDL_LogCritical(SDL_LOG_CATEGORY_APPLICATION, "Failed to open audio capture device: %s", SDL_GetError());
100+
SDL_Quit();
101+
}
102+
103+
// read characteristics of opened capture device
104+
SDL_Log("Opened audio capture device %i: %s", app->audioDeviceID, SDL_GetAudioDeviceName(selectedAudioDevice, true));
105+
SDL_Log("Sample rate: %i, frequency: %i, channels: %i, format: %i", have.samples, have.freq, have.channels, have.format);
106+
app->audioChannelsCount = have.channels;
107+
app->audioSampleRate = have.freq;
108+
app->audioSampleCount = have.samples;
109+
app->audioFormat = have.format;
57110

58111
return 1;
59112
}
60113

114+
void beginAudioCapture(projectMApp *app) {
115+
// allocate a buffer to store PCM data for feeding in
116+
unsigned int maxSamples = app->audioChannelsCount * app->audioSampleCount;
117+
app->pcmBuffer = (unsigned char *) malloc(maxSamples);
118+
SDL_PauseAudioDevice(app->audioDeviceID, false);
119+
// app->pm->pcm()->initPCM(maxSamples);
120+
}
121+
122+
void endAudioCapture(projectMApp *app) {
123+
free(app->pcmBuffer);
124+
SDL_PauseAudioDevice(app->audioDeviceID, true);
125+
}
126+
61127
void keyHandler(projectMApp *app, SDL_Event *sdl_evt) {
62128
projectMEvent evt;
63129
projectMKeycode key;
@@ -74,38 +140,40 @@ void keyHandler(projectMApp *app, SDL_Event *sdl_evt) {
74140
}
75141
}
76142

77-
void renderFrame(projectMApp *app) {
143+
void addFakePCM(projectMApp *app) {
78144
int i;
79145
short pcm_data[2][512];
80-
SDL_Event evt;
81-
82-
SDL_PollEvent(&evt);
83-
switch (evt.type) {
84-
case SDL_KEYDOWN:
85-
keyHandler(app, &evt);
86-
break;
87-
case SDL_QUIT:
88-
app->done = true;
89-
break;
90-
}
91-
92146
/** Produce some fake PCM data to stuff into projectM */
93147
for ( i = 0 ; i < 512 ; i++ ) {
94148
if ( i % 2 == 0 ) {
95149
pcm_data[0][i] = (float)( rand() / ( (float)RAND_MAX ) * (pow(2,14) ) );
96150
pcm_data[1][i] = (float)( rand() / ( (float)RAND_MAX ) * (pow(2,14) ) );
97-
} else {
151+
} else {
98152
pcm_data[0][i] = (float)( rand() / ( (float)RAND_MAX ) * (pow(2,14) ) );
99153
pcm_data[1][i] = (float)( rand() / ( (float)RAND_MAX ) * (pow(2,14) ) );
100-
}
154+
}
101155
if ( i % 2 == 1 ) {
102156
pcm_data[0][i] = -pcm_data[0][i];
103157
pcm_data[1][i] = -pcm_data[1][i];
104-
}
158+
}
105159
}
106-
160+
107161
/** Add the waveform data */
108162
app->pm->pcm()->addPCM16(pcm_data);
163+
}
164+
165+
void renderFrame(projectMApp *app) {
166+
SDL_Event evt;
167+
168+
SDL_PollEvent(&evt);
169+
switch (evt.type) {
170+
case SDL_KEYDOWN:
171+
keyHandler(app, &evt);
172+
break;
173+
case SDL_QUIT:
174+
app->done = true;
175+
break;
176+
}
109177

110178
glClearColor( 0.0, 0.0, 0.0, 0.0 );
111179
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
@@ -123,21 +191,15 @@ int main( int argc, char *argv[] ) {
123191
int width = 784,
124192
height = 784;
125193

126-
SDL_Init(SDL_INIT_VIDEO);
127-
128-
// get an audio input device
129-
if (! selectAudioInput(&app)) {
130-
fprintf(stderr, "Failed to open audio input device\n");
131-
return 1;
132-
}
194+
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
133195

134196
app.win = SDL_CreateWindow("projectM", 0, 0, width, height, 0);
135197
app.rend = SDL_CreateRenderer(app.win, 0, SDL_RENDERER_ACCELERATED);
136198
if (! app.rend) {
137199
fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError());
138200
return PROJECTM_ERROR;
139201
}
140-
SDL_SetWindowTitle(app.win, "SDL Fun Party Time");
202+
SDL_SetWindowTitle(app.win, "projectM Visualizer");
141203
printf("SDL init version 2\n");
142204

143205
#ifdef PANTS
@@ -170,6 +232,10 @@ int main( int argc, char *argv[] ) {
170232
app.pm = new projectM(app.settings);
171233
app.pm->selectRandom(true);
172234
app.pm->projectM_resetGL(width, height);
235+
236+
// get an audio input device
237+
openAudioInput(&app);
238+
beginAudioCapture(&app);
173239

174240
// standard main loop
175241
const Uint32 frame_delay = 1000/FPS;

0 commit comments

Comments
 (0)