Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit df35f85

Browse files
Add keyboard input and audio recording support to emscripten sample app.
1 parent 545722d commit df35f85

File tree

2 files changed

+186
-122
lines changed

2 files changed

+186
-122
lines changed

‎src/projectM-emscripten/README.md‎

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,7 @@
22

33
This application is a sample entry point for the emscripten-built version of projectM.
44

5-
It's a very basic application, only displaying the "idle" preset. Missing features:
6-
7-
- No audio capture capabilities, only renders fake random audio.
8-
- Input/hotkey support is not implemented.
9-
- No presets are packaged into the virtual file system.
5+
It's a very basic application, only displaying the "idle" preset. No presets are currently packaged into the virtual file system.
106

117
## Limitations
128

‎src/projectM-emscripten/projectM_SDL_emscripten.cpp‎

Lines changed: 185 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#include <math.h>
88
#include <projectM.h>
9+
#include <sdltoprojectM.h>
910

1011
#include <emscripten.h>
1112
#include <GL/gl.h>
@@ -17,139 +18,211 @@
1718

1819
const float FPS = 60;
1920

20-
typedef struct {
21-
projectm_handle pm;
22-
SDL_Window *win;
23-
SDL_Renderer *rend;
24-
bool done;
21+
struct projectMApp
22+
{
23+
projectm_handle pm{ nullptr };
24+
SDL_Window* win{ nullptr };
25+
SDL_Renderer* rend{ nullptr };
26+
bool done{ false };
2527
projectm_settings settings;
26-
SDL_AudioDeviceID audioInputDevice;
27-
} projectMApp;
28+
SDL_AudioDeviceID audioInputDevice{ 0 };
29+
int audioInputDevicesCount{ 0 };
30+
int audioChannelsCount{ 0 };
31+
bool isFullscreen{ false };
32+
};
2833

2934
projectMApp app;
3035

31-
int selectAudioInput(projectMApp *application) {
32-
int i, count = SDL_GetNumAudioDevices(1);
36+
void audioInputCallbackF32(void* userdata, unsigned char* stream, int len)
37+
{
38+
if (app.audioChannelsCount == 1)
39+
{
40+
projectm_pcm_add_float_1ch_data(app.pm, reinterpret_cast<float*>(stream), len / sizeof(float));
41+
}
42+
else if (app.audioChannelsCount == 2)
43+
{
44+
projectm_pcm_add_float_2ch_data(app.pm, reinterpret_cast<float*>(stream), len / sizeof(float));
45+
}
46+
else
47+
{
48+
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Multichannel audio not supported");
49+
}
50+
}
51+
52+
bool selectAudioInput(projectMApp* application)
53+
{
54+
app.audioInputDevicesCount = SDL_GetNumAudioDevices(1);
55+
56+
if (!app.audioInputDevicesCount)
57+
{
58+
fprintf(stderr, "No audio input capture devices detected. Faking audio using random data.\n");
59+
return false;
60+
}
61+
62+
printf("count: %d\n", app.audioInputDevicesCount);
63+
for (int i = 0; i < app.audioInputDevicesCount; ++i)
64+
{
65+
printf("Audio device %d: %s\n", i, SDL_GetAudioDeviceName(i, 1));
66+
}
3367

34-
if (! count) {
35-
fprintf(stderr, "No audio input capture devices detected\n");
36-
return 0;
68+
SDL_AudioSpec want, have;
69+
70+
SDL_zero(want);
71+
want.freq = 44100;
72+
want.format = AUDIO_F32;
73+
want.channels = 2;
74+
want.samples = projectm_pcm_get_max_samples();
75+
want.callback = &audioInputCallbackF32;
76+
77+
// Start with first device
78+
app.audioInputDevice = SDL_OpenAudioDevice(SDL_GetAudioDeviceName(0, true), true, &want, &have, 0);
79+
app.audioChannelsCount = have.channels;
80+
81+
if (have.channels == 1 || have.channels == 2)
82+
{
83+
SDL_PauseAudioDevice(app.audioInputDevice, false);
84+
printf("Audio device specs: Channels=%d, Samplerate=%d, Format=%d\n", have.channels, have.freq, have.format);
85+
}
86+
return true;
87+
}
88+
89+
void keyHandler(const SDL_Event& sdl_evt)
90+
{
91+
projectMEvent evt;
92+
projectMKeycode key;
93+
projectMModifier mod;
94+
auto sdl_mod = static_cast<SDL_Keymod>(sdl_evt.key.keysym.mod);
95+
SDL_Keycode sdl_keycode = sdl_evt.key.keysym.sym;
96+
bool keyMod = false;
97+
98+
// Left or Right Gui or Left Ctrl
99+
if (sdl_mod & KMOD_LGUI || sdl_mod & KMOD_RGUI || sdl_mod & KMOD_LCTRL)
100+
{
101+
keyMod = true;
37102
}
38103

39-
printf("count: %d\n", count);
40-
for (i = 0; i < count; ++i) {
41-
printf("Audio device %d: %s\n", i, SDL_GetAudioDeviceName(i, 0));
104+
// handle keyboard input (for our app first, then projectM)
105+
switch (sdl_keycode)
106+
{
107+
case SDLK_BACKSPACE:
108+
projectm_delete_search_text(app.pm);
109+
break;
110+
case SDLK_RETURN:
111+
if (!projectm_is_text_input_active(app.pm, false))
112+
{
113+
SDL_StartTextInput();
114+
}
115+
break;
116+
case SDLK_ESCAPE:
117+
if (projectm_is_text_input_active(app.pm, false))
118+
{
119+
SDL_StopTextInput();
120+
}
121+
break;
122+
case SDLK_f:
123+
if (keyMod)
124+
{
125+
app.isFullscreen = !app.isFullscreen;
126+
SDL_SetWindowFullscreen(app.win, app.isFullscreen ? SDL_WINDOW_FULLSCREEN : 0);
127+
return; // handled
128+
}
129+
break;
130+
131+
case SDLK_SPACE:
132+
if (!projectm_is_text_input_active(app.pm, true))
133+
{
134+
projectm_lock_preset(app.pm, !projectm_is_preset_locked(app.pm));
135+
}
136+
break;
137+
42138
}
43139

44-
return 1;
140+
// translate into projectM codes and perform default projectM handler
141+
evt = sdl2pmEvent(&sdl_evt);
142+
mod = sdl2pmModifier(sdl_mod);
143+
key = sdl2pmKeycode(sdl_keycode, sdl_mod);
144+
projectm_key_handler(app.pm, evt, key, mod);
45145
}
46146

47-
void renderFrame() {
48-
int i;
49-
short pcm_data[2][512];
147+
void renderFrame()
148+
{
50149
SDL_Event evt;
51150

52151
SDL_PollEvent(&evt);
53-
switch (evt.type) {
152+
switch (evt.type)
153+
{
54154
case SDL_KEYDOWN:
55-
// ...
155+
keyHandler(evt);
156+
break;
157+
case SDL_TEXTINPUT:
158+
if (projectm_is_text_input_active(app.pm, true))
159+
{
160+
projectm_set_search_text(app.pm, evt.text.text);
161+
projectm_populate_preset_menu(app.pm);
162+
}
56163
break;
57164
case SDL_QUIT:
58165
app.done = true;
59166
break;
60167
}
61168

62-
63-
// projectMEvent evt;
64-
// projectMKeycode key;
65-
// projectMModifier mod;
66-
//
67-
// /** Process SDL events */
68-
// SDL_Event event;
69-
// while ( SDL_PollEvent( &event ) ) {
70-
// /** Translate into projectM codes and process */
71-
// evt = sdl2pmEvent( event );
72-
// key = sdl2pmKeycode( event.key.keysym.sym );
73-
// mod = sdl2pmModifier( (SDLMod)event.key.keysym.mod );
74-
// if ( evt == PROJECTM_KEYDOWN ) {
75-
// pm->key_handler( evt, key, mod );
76-
// }
77-
// }
78-
79-
/** Produce some fake PCM data to stuff into projectM */
80-
for ( i = 0 ; i < 512 ; i++ ) {
81-
if ( i % 2 == 0 ) {
82-
pcm_data[0][i] = (float)( rand() / ( (float)RAND_MAX ) * (pow(2,14) ) );
83-
pcm_data[1][i] = (float)( rand() / ( (float)RAND_MAX ) * (pow(2,14) ) );
84-
} else {
85-
pcm_data[0][i] = (float)( rand() / ( (float)RAND_MAX ) * (pow(2,14) ) );
86-
pcm_data[1][i] = (float)( rand() / ( (float)RAND_MAX ) * (pow(2,14) ) );
87-
}
88-
if ( i % 2 == 1 ) {
89-
pcm_data[0][i] = -pcm_data[0][i];
90-
pcm_data[1][i] = -pcm_data[1][i];
91-
}
169+
if (app.audioInputDevicesCount == 0)
170+
{
171+
short pcm_data[2][512];
172+
173+
/** Produce some fake PCM data to stuff into projectM */
174+
for (int i = 0; i < 512; i++)
175+
{
176+
if (i % 2 == 0)
177+
{
178+
pcm_data[0][i] = (float) (rand() / ((float) RAND_MAX) * (pow(2, 14)));
179+
pcm_data[1][i] = (float) (rand() / ((float) RAND_MAX) * (pow(2, 14)));
180+
}
181+
else
182+
{
183+
pcm_data[0][i] = (float) (rand() / ((float) RAND_MAX) * (pow(2, 14)));
184+
pcm_data[1][i] = (float) (rand() / ((float) RAND_MAX) * (pow(2, 14)));
185+
}
186+
if (i % 2 == 1)
187+
{
188+
pcm_data[0][i] = -pcm_data[0][i];
189+
pcm_data[1][i] = -pcm_data[1][i];
190+
}
191+
}
192+
193+
/** Add the waveform data */
194+
projectm_pcm_add_16bit_2ch_512(app.pm, pcm_data);
92195
}
93196

94-
/** Add the waveform data */
95-
projectm_pcm_add_16bit_2ch_512(app.pm, pcm_data);
96197

97-
glClearColor(0.0, 0.5, 0.0, 0.0);
98-
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
198+
glClearColor(0.0, 0.5, 0.0, 0.0);
199+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
99200

100201
projectm_render_frame(app.pm);
101202
glFlush();
102203

103204
SDL_RenderPresent(app.rend);
104205
}
105206

106-
int main( int argc, char *argv[] ) {
107-
app.done = 0;
108-
109-
int width = 784,
110-
height = 784;
111-
207+
int main(int argc, char* argv[])
208+
{
209+
int width = 1024;
210+
int height = 1024;
112211

113212
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO);
114213

115-
// get an audio input device
116-
if (! selectAudioInput(&app)) {
117-
fprintf(stderr, "Failed to open audio input device\n");
118-
return 1;
119-
}
120-
121-
// SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 );
122-
// SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 );
123-
// SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 );
124-
// SDL_GL_SetAttribute( SDL_GL_ACCUM_RED_SIZE, 8 );
125-
// SDL_GL_SetAttribute( SDL_GL_ACCUM_GREEN_SIZE, 8 );
126-
// SDL_GL_SetAttribute( SDL_GL_ACCUM_BLUE_SIZE, 8 );
127-
// SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
128-
// SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 );
129-
// SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
130-
131-
app.win = SDL_CreateWindow("SDL Fun Party Time", 50, 50, width, height, 0);
214+
app.win = SDL_CreateWindow("projectM", 50, 50, width, height, 0);
132215
app.rend = SDL_CreateRenderer(app.win, 0, SDL_RENDERER_ACCELERATED);
133-
if (! app.rend) {
216+
if (!app.rend)
217+
{
134218
fprintf(stderr, "Failed to create renderer: %s\n", SDL_GetError());
135219
return 1;
136220
}
137-
SDL_SetWindowTitle(app.win, "SDL Fun Party Time");
138-
printf("SDL init version 2\n");
139221

140-
141-
#ifdef PANTS
142-
if ( fsaa ) {
143-
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLEBUFFERS, &value );
144-
printf( "SDL_GL_MULTISAMPLEBUFFERS: requested 1, got %d\n", value );
145-
SDL_GL_GetAttribute( SDL_GL_MULTISAMPLESAMPLES, &value );
146-
printf( "SDL_GL_MULTISAMPLESAMPLES: requested %d, got %d\n", fsaa, value );
147-
}
148-
#endif
149222
app.settings.mesh_x = 48;
150223
app.settings.mesh_y = 32;
151-
app.settings.fps = FPS;
152-
app.settings.texture_size = 2048; // idk?
224+
app.settings.fps = FPS;
225+
app.settings.texture_size = 1024;
153226
app.settings.window_width = width;
154227
app.settings.window_height = height;
155228
app.settings.soft_cut_duration = 3; // seconds
@@ -170,42 +243,37 @@ int main( int argc, char *argv[] ) {
170243
projectm_set_window_size(app.pm, width, height);
171244
printf("resetGL\n");
172245

246+
// get an audio input device
247+
if (!selectAudioInput(&app))
248+
{
249+
fprintf(stderr, "Failed to open audio input device\n");
250+
return 1;
251+
}
252+
173253
// Allocate a new a stream given the current directory name
174-
DIR* m_dir;
175-
if ((m_dir = opendir("/")) == NULL)
254+
DIR* m_dir;
255+
if ((m_dir = opendir("/")) == nullptr)
176256
{
177257
printf("error opening /\n");
178-
} else {
179-
180-
struct dirent * dir_entry;
181-
while ((dir_entry = readdir(m_dir)) != NULL)
182-
{
183-
printf("%s\n", dir_entry->d_name);
184-
}
185-
}
258+
}
259+
else
260+
{
261+
struct dirent* dir_entry;
262+
while ((dir_entry = readdir(m_dir)) != nullptr)
263+
{
264+
printf("%s\n", dir_entry->d_name);
265+
}
266+
}
186267

187268
auto playlistSize = projectm_get_playlist_size(app.pm);
188-
for(unsigned int i = 0; i < playlistSize; i++) {
269+
for (unsigned int i = 0; i < playlistSize; i++)
270+
{
189271
auto presetName = projectm_get_preset_name(app.pm, i);
190272
printf("%u\t%s\n", i, presetName);
191273
projectm_free_string(presetName);
192274
}
193275

194-
// mainloop. non-emscripten version here for comparison/testing
195-
#ifdef EMSCRIPTEN
196276
emscripten_set_main_loop(renderFrame, 0, 0);
197-
#else
198-
// standard main loop
199-
const Uint32 frame_delay = 1000/FPS;
200-
Uint32 last_time = SDL_GetTicks();
201-
while (! app.done) {
202-
renderFrame(&app);
203-
Uint32 elapsed = SDL_GetTicks() - last_time;
204-
if (elapsed < frame_delay)
205-
SDL_Delay(frame_delay - elapsed);
206-
last_time = SDL_GetTicks();
207-
}
208-
#endif
209277

210278
return 0;
211279
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /