void iter() {
  printf("frame: %d\n", ++counter);

  emscripten_async_call(acall, 0, counter % 2); // 0 or 1 millis, try to execute this *before* the sync callback finishes, which would be bad

  // ensure we don't 'recurse' with the main loop sending is back in before the synchronous operation callback finishes the rest of this trace
  assert(nesting == 0);
  nesting++;
  emscripten_sleep(500);
  assert(nesting == 1);
  nesting = 2;

  if (counter % 3 == 2) {
    // second sleep every 3rd frame, to test sleep when returning from a sleep
    printf(" (second sleep)\n");
    assert(nesting == 2);
    nesting = 3;
    emscripten_sleep(1000);
    assert(nesting == 3);
  };

  nesting = 0;

  if (counter == 10) {
    assert(acall_counter == 9 /* the tenth is about to execute, but not yet! */ );
    finish(121); // if we got here without hitting any assertions, all is well
    emscripten_cancel_main_loop();
  }
}
Ejemplo n.º 2
0
static bool sleepWithTimeout(int duration, int * timeout) {
  if (*timeout >= duration) {
    emscripten_sleep(duration);
    *timeout -= duration;
    return false;
  } else {
    emscripten_sleep(*timeout);
    *timeout = 0;
    return true;
  }
}
int main(void) {
    printf("No yield:\n");
    emscripten_sleep(500);
    printf("With yield:\n");
    emscripten_sleep_with_yield(500);
    printf("Again no yield:\n");
    emscripten_sleep(500);
    printf("Done!\n");
    REPORT_RESULT(1);
    return 0;
}
Ejemplo n.º 4
0
int main(int argc, char **argv) {
  SDL_Init(SDL_INIT_VIDEO);
  SDL_Surface *screen = SDL_SetVideoMode(600, 450, 32, SDL_HWSURFACE);

#ifdef TEST_EMSCRIPTEN_SDL_SETEVENTHANDLER
  emscripten_SDL_SetEventHandler(EventHandler, 0);
#endif

  emscripten_set_main_loop(one, 0, 0);

  emscripten_run_script("keydown(1250);keydown(38);keyup(38);keyup(1250);"); // alt, up
  emscripten_run_script("keydown(1248);keydown(1249);keydown(40);keyup(40);keyup(1249);keyup(1248);"); // ctrl, shift, down
  emscripten_run_script("keydown(37);keyup(37);"); // left
  emscripten_run_script("keydown(39);keyup(39);"); // right

#ifdef TEST_SLEEP
  printf("sleep...\n");
  emscripten_sleep(2000);
  //emscripten_sleep_with_yield(1);
  printf("rise!\n");
#endif

  emscripten_run_script("keydown(65);keyup(65);"); // a
  emscripten_run_script("keydown(66);keyup(66);"); // b
  emscripten_run_script("keydown(100);keyup(100);"); // trigger the end

  return 0;
}
Ejemplo n.º 5
0
int Web_nh_poskey(int * x, int * y, int * mod)
{ 
    while(Web_keybuffer_empty() && Web_mousebuffer_empty()) emscripten_sleep(10);
    if(!Web_keybuffer_empty()) return Web_getch();
    Web_save_mouse(x, y, mod);
    return 0;
}
Ejemplo n.º 6
0
void one(char *data, int size) {
  int *x = (int*)data;
  int num = size/sizeof(int);
  for (int i = 0; i < num; i++) {
    x[i] += 1234;
  }
  emscripten_sleep(1000);
  emscripten_worker_respond(data, size);
}
Ejemplo n.º 7
0
void loop(void) {
  emscripten_sleep(1);
  loops++;
  printf("loop:  mains, inners, nevers, loops: %d, %d, %d, %d\n", mains, inners, nevers, loops);
  if (loops > 5) {
    printf("done looping\n");
    emscripten_cancel_main_loop();
    assert(mains == 1); // never re-enter main
    assert(inners == 1); // never re-enter inner
    assert(nevers == 0); // never reach never
    int result = 1;
    REPORT_RESULT();
    return;
  }
}
Ejemplo n.º 8
0
static void morphdraw()
{
    int s = STATE > 0 ? (STATE < MTIME ? STATE : MTIME) : 0;
    int mul = s * 256 / MTIME;
    int mul1 = 256 - mul;
    int i;
    int size = aa_imgwidth(context) * (aa_imgheight(context) - YSTART * 2);
    char *c = context->imagebuffer + aa_imgwidth(context) * 2 * YSTART;
    for (i = 0; i < size; i++, c++) {
	*c = (source[i] * mul1 + target[i] * mul) >> 8;
    }
    aa_fastrender(context, 0, YSTART, aa_scrwidth(context), aa_scrheight(context));
    aa_flush(context);
    emscripten_sleep(1);
}
Ejemplo n.º 9
0
static void toblack1()
{
    int x, y, mul1, mul2 = 0, pos;
    int minpos = 0;
    unsigned char *b1 = bckup, *b2 = bckup1;
    pos = STAGE * (aa_imgheight(context) + aa_imgheight(context)) / (endtime - starttime) - aa_imgheight(context);
    for (y = 0; y < aa_imgheight(context); y++) {
	mul1 = (y - pos);
	if (mul1 < 0)
	    mul1 = 0;
	else
	    mul1 = mul1 * 256 * 4 / aa_imgheight(context);
	if (mul1 > 256)
	    mul1 = 256;
	mul2 = (y - pos - aa_imgheight(context));
	if (mul2 < 0)
	    mul2 = 0;
	else
	    mul2 = mul2 * 256 * 8 / aa_imgheight(context);
	if (mul2 > 256)
	    mul2 = 256;
	if (mul2 == 0)
	    minpos = y;
	mul1 -= mul2;
	for (x = 0; x < aa_imgwidth(context); x++) {
	    aa_putpixel(context, x, y,
			(mul1 * (int) (*b1) + mul2 * (int) (*b2)) / 256);
	    b1++;
	    b2++;
	}
    }
    minpos = pos + 3 * aa_imgheight(context) / 4;
    if (minpos < 0)
	minpos = 0;
    if (minpos > aa_imgheight(context))
	minpos = aa_imgheight(context);
    aa_render(context, params, 0, 0, aa_imgwidth(context), minpos);
    aa_flush(context);
    emscripten_sleep(1);
}
Ejemplo n.º 10
0
int BatchFile::ReadLine(char * line) {
  printf("Sleep-->\n");
  emscripten_sleep(300);
  printf("<--Sleep\n");
  return 1;
}
void sleeper() {
  emscripten_sleep(100);
}
Ejemplo n.º 12
0
void tl_sleep(int time)
{
    emscripten_sleep(time / 1000);
}
Ejemplo n.º 13
0
void Web_get_nh_event() { emscripten_sleep(1); }
Ejemplo n.º 14
0
void Web_display_nhwindow(winid window, BOOLEAN_P blocking) { emscripten_sleep(1); }
Ejemplo n.º 15
0
void Web_delay_output() { emscripten_sleep(50); }
Ejemplo n.º 16
0
int Web_nhgetch()
{ 
    while(Web_keybuffer_empty()) emscripten_sleep(10);
    return Web_getch();
}
Ejemplo n.º 17
0
void Web_wait_synch() { emscripten_sleep(1); }
Ejemplo n.º 18
0
void Web_mark_synch() { emscripten_sleep(1); }
Ejemplo n.º 19
0
static inline void HandleEvent(struct Game* game, ALLEGRO_EVENT* ev) {
	switch (ev->type) {
		case ALLEGRO_EVENT_DISPLAY_HALT_DRAWING:
			PauseExecution(game);
			al_acknowledge_drawing_halt(game->display);
			break;

		case ALLEGRO_EVENT_DISPLAY_RESUME_DRAWING:
			al_acknowledge_drawing_resume(game->display);
			ReloadGamestates(game);
			ResumeExecution(game);
			break;

		case ALLEGRO_EVENT_DISPLAY_SWITCH_OUT:
			if (game->config.autopause) {
				PrintConsole(game, "Focus lost, autopausing...");
				PauseExecution(game);
			}
			break;

		case ALLEGRO_EVENT_DISPLAY_SWITCH_IN:
			if (game->config.autopause) {
				if (game->config.debug.enabled && game->config.debug.livereload) {
					ReloadCode(game);
				}
				ResumeExecution(game);
			}
			break;

		case ALLEGRO_EVENT_DISPLAY_RESIZE:
			PrintConsole(game, "Resize event: %dx%d", ev->display.width, ev->display.height);

#ifdef LIBSUPERDERPY_IMGUI
			ImGui_ImplAllegro5_InvalidateDeviceObjects();
#endif
			al_acknowledge_resize(game->display);
#ifdef LIBSUPERDERPY_IMGUI
			ImGui_ImplAllegro5_CreateDeviceObjects();
#endif

			// SetupViewport can be expensive, so don't do it when the resize event is already outdated or doesn't change anything
			if (((ev->display.width != game->_priv.window_width) || (ev->display.height != game->_priv.window_height)) &&
				(ev->display.width == al_get_display_width(game->display)) && (ev->display.height == al_get_display_height(game->display))) {
				SetupViewport(game);
			}

			break;
		case ALLEGRO_EVENT_KEY_DOWN:
#ifdef ALLEGRO_ANDROID
			if ((ev->keyboard.keycode == ALLEGRO_KEY_MENU) || (ev->keyboard.keycode == ALLEGRO_KEY_TILDE) || (ev->keyboard.keycode == ALLEGRO_KEY_BACKQUOTE)) {
#else
			if ((ev->keyboard.keycode == ALLEGRO_KEY_TILDE) || (ev->keyboard.keycode == ALLEGRO_KEY_BACKQUOTE)) {
#endif
				game->_priv.showconsole = !game->_priv.showconsole;
				if ((ev->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL) && (game->config.debug.enabled)) {
					game->_priv.showtimeline = game->_priv.showconsole;
				}
			}

			if (ev->keyboard.keycode == ALLEGRO_KEY_F12) {
				DrawGamestates(game);
				int flags = al_get_new_bitmap_flags();
				al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP);
				ALLEGRO_BITMAP* bitmap = al_create_bitmap(al_get_display_width(game->display), al_get_display_height(game->display));
				al_set_new_bitmap_flags(flags);
				ALLEGRO_BITMAP* target = al_get_target_bitmap();
				al_set_target_bitmap(bitmap);
				al_draw_bitmap(al_get_backbuffer(game->display), 0, 0, 0);
				al_set_target_bitmap(target);
				PrintConsole(game, "Screenshot made! Storing...");

				struct ScreenshotThreadData* data = malloc(sizeof(struct ScreenshotThreadData));
				data->game = game;
				data->bitmap = bitmap;
#ifndef LIBSUPERDERPY_SINGLE_THREAD
				al_run_detached_thread(ScreenshotThread, data);
#else
				ScreenshotThread(data);
#endif
			}

			break;
		default:
			break;
	}

#ifdef MAEMO5
	// on Maemo we get mouse events instead of touch ones, so we'll rewrite them by ourselves

	if ((ev->type == ALLEGRO_EVENT_MOUSE_AXES) || (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) || (ev->type == ALLEGRO_EVENT_MOUSE_BUTTON_UP)) {
		switch (ev->type) {
			case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
				ev->type = ALLEGRO_EVENT_TOUCH_BEGIN;
				break;
			case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
				ev->type = ALLEGRO_EVENT_TOUCH_END;
				break;
			case ALLEGRO_EVENT_MOUSE_AXES:
				ev->type = ALLEGRO_EVENT_TOUCH_MOVE;
				break;
			default:
				break;
		}
		ALLEGRO_DISPLAY* display = ev->mouse.display;
		float dx = ev->mouse.dx;
		float dy = ev->mouse.dy;
		float x = ev->mouse.x;
		float y = ev->mouse.y;
		double timestamp = ev->mouse.timestamp;

		ev->touch.display = display;
		ev->touch.dx = dx;
		ev->touch.dy = dy;
		ev->touch.id = 0;
		ev->touch.primary = true;
		ev->touch.source = (ALLEGRO_TOUCH_INPUT*)al_get_touch_input_event_source();
		ev->touch.timestamp = timestamp;
		ev->touch.x = x;
		ev->touch.y = y;
	}
#endif
}

static inline void HandleDebugEvent(struct Game* game, ALLEGRO_EVENT* ev) {
	switch (ev->type) {
		case ALLEGRO_EVENT_KEY_DOWN:
			switch (ev->keyboard.keycode) {
				case ALLEGRO_KEY_F1:
					if (!game->_priv.paused) {
						PauseExecution(game);
					} else {
						ReloadCode(game);
						ResumeExecution(game);
					}
					break;
				case ALLEGRO_KEY_F9:
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(60.0);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: 1.00x");
					break;
				case ALLEGRO_KEY_F10: {
					double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting
					speed -= 10;
					if (speed < 10) { speed = 10; }
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0);
				} break;
				case ALLEGRO_KEY_F11: {
					double speed = ALLEGRO_BPS_TO_SECS(game->_priv.speed); // inverting
					speed += 10;
					if (speed > 600) { speed = 600; }
					game->_priv.speed = ALLEGRO_BPS_TO_SECS(speed);
					game->_priv.showconsole = true;
					PrintConsole(game, "DEBUG: Gameplay speed: %.2fx", speed / 60.0);
				} break;
			}

			break;
		default:
			break;
	}
}

static inline bool MainloopEvents(struct Game* game) {
	do {
		ALLEGRO_EVENT ev;

		if (game->_priv.paused && !IS_EMSCRIPTEN) {
			// there's no frame flipping when paused, so avoid pointless busylooping
			al_wait_for_event(game->_priv.event_queue, &ev);
		} else if (!al_get_next_event(game->_priv.event_queue, &ev)) {
			break;
		}

#ifdef LIBSUPERDERPY_IMGUI
		ImGui_ImplAllegro5_ProcessEvent(&ev);
		switch (ev.type) {
			case ALLEGRO_EVENT_KEY_CHAR:
			case ALLEGRO_EVENT_KEY_DOWN:
			case ALLEGRO_EVENT_KEY_UP:
				if (igGetIO()->WantCaptureKeyboard) {
					continue;
				}
				break;
			case ALLEGRO_EVENT_MOUSE_AXES:
			case ALLEGRO_EVENT_MOUSE_BUTTON_DOWN:
			case ALLEGRO_EVENT_MOUSE_BUTTON_UP:
			case ALLEGRO_EVENT_TOUCH_BEGIN:
			case ALLEGRO_EVENT_TOUCH_CANCEL:
			case ALLEGRO_EVENT_TOUCH_END:
			case ALLEGRO_EVENT_TOUCH_MOVE:
				if (igGetIO()->WantCaptureMouse) {
					continue;
				}
				break;
			default:
				break;
		}
#endif

		if (game->_priv.params.handlers.event) {
			if ((*game->_priv.params.handlers.event)(game, &ev)) {
				continue;
			}
		}

		if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
			EventGamestates(game, &ev);
			return false;
		}

		HandleEvent(game, &ev);

		if (game->config.debug.enabled) {
			HandleDebugEvent(game, &ev);
		}

		EventGamestates(game, &ev);

	} while (!al_is_event_queue_empty(game->_priv.event_queue));
	return true;
}

static inline bool MainloopTick(struct Game* game) {
	if (game->_priv.paused) {
		return true;
	}

	struct Gamestate* tmp = game->_priv.gamestates;

#ifdef __EMSCRIPTEN__
	emscripten_pause_main_loop();
#endif

	game->_priv.loading.to_load = 0;
	game->_priv.loading.loaded = 0;
	game->_priv.loading.lock = true;
	game->loading.progress = 0;

	// TODO: support gamestate dependences/ordering
	while (tmp) {
		if (tmp->pending_stop) {
			PrintConsole(game, "Stopping gamestate \"%s\"...", tmp->name);
			game->_priv.current_gamestate = tmp;
			(*tmp->api->stop)(game, tmp->data);
			tmp->started = false;
			tmp->pending_stop = false;
			PrintConsole(game, "Gamestate \"%s\" stopped successfully.", tmp->name);
		}

		if (tmp->pending_load) { game->_priv.loading.to_load++; }
		tmp = tmp->next;
	}

	tmp = game->_priv.gamestates;

	while (tmp) {
		if (tmp->pending_unload) {
#ifdef __EMSCRIPTEN__
			al_detach_voice(game->audio.v);
#endif
			PrintConsole(game, "Unloading gamestate \"%s\"...", tmp->name);
			tmp->loaded = false;
			tmp->pending_unload = false;
			game->_priv.current_gamestate = tmp;
			(*tmp->api->unload)(game, tmp->data);
			PrintConsole(game, "Gamestate \"%s\" unloaded successfully.", tmp->name);
#ifdef __EMSCRIPTEN__
			al_attach_mixer_to_voice(game->audio.mixer, game->audio.v);
#endif
		}
		if (tmp->pending_load) {
#ifdef __EMSCRIPTEN__
			al_detach_voice(game->audio.v);
#endif
			if (tmp->show_loading && game->_priv.loading.gamestate->open) {
				(*game->_priv.loading.gamestate->api->start)(game, game->_priv.loading.gamestate->data);
			}

			if (!tmp->api) {
				if (!OpenGamestate(game, tmp, true) || !LinkGamestate(game, tmp)) {
					tmp->pending_load = false;
					tmp->pending_start = false;
					continue;
				}
			}
			if (tmp->api) {
				PrintConsole(game, "Loading gamestate \"%s\"...", tmp->name);
				game->_priv.loading.progress = 0;

				game->_priv.loading.current = tmp;
				game->_priv.current_gamestate = tmp;

				struct GamestateLoadingThreadData data = {.game = game, .gamestate = tmp, .bitmap_flags = al_get_new_bitmap_flags()};
				game->_priv.loading.in_progress = true;
				double time = al_get_time();
				game->_priv.loading.time = time;

				CalculateProgress(game);
				if (tmp->show_loading) {
					game->loading.shown = true;
					DrawGamestates(game);
					DrawConsole(game);
					al_flip_display();
#ifdef __EMSCRIPTEN__
					emscripten_sleep(0);
#endif
				}
#ifndef LIBSUPERDERPY_SINGLE_THREAD
				al_run_detached_thread(GamestateLoadingThread, &data);
				while (game->_priv.loading.in_progress) {
					double delta = al_get_time() - game->_priv.loading.time;
					game->time += delta; // TODO: ability to disable passing time during loading
					game->_priv.loading.time += delta;
					if (game->loading.shown && game->_priv.loading.gamestate->open) {
						(*game->_priv.loading.gamestate->api->logic)(game, game->_priv.loading.gamestate->data, delta);
					}
					DrawGamestates(game);
					if (game->_priv.texture_sync) {
						al_convert_memory_bitmaps();
						game->_priv.texture_sync = false;
						al_signal_cond(game->_priv.texture_sync_cond);
						game->_priv.loading.time = al_get_time(); // TODO: rethink time management during loading
					}
					DrawConsole(game);
					al_flip_display();

					if (game->_priv.bsod_sync) {
						al_set_target_bitmap(NULL);
						game->_priv.bsod_sync = false;
						al_signal_cond(game->_priv.bsod_cond);
					}

					al_lock_mutex(game->_priv.bsod_mutex);
					while (game->_priv.in_bsod) {
						al_wait_cond(game->_priv.bsod_cond, game->_priv.bsod_mutex);
					}
					al_unlock_mutex(game->_priv.bsod_mutex);
				}
#else
				GamestateLoadingThread(&data);
				DrawGamestates(game);
				DrawConsole(game);
				al_flip_display();
#ifdef __EMSCRIPTEN__
				emscripten_sleep(0);
#endif
				al_convert_memory_bitmaps();
#endif

				al_set_new_bitmap_flags(data.bitmap_flags);

				ReloadShaders(game, false);

				if (tmp->api->post_load) {
					PrintConsole(game, "[%s] Post-loading...", tmp->name);
					tmp->api->post_load(game, tmp->data);
				}

				game->_priv.loading.progress++;
				CalculateProgress(game);
				PrintConsole(game, "Gamestate \"%s\" loaded successfully in %f seconds.", tmp->name, al_get_time() - time);
				game->_priv.loading.loaded++;

				DrawGamestates(game);
				DrawConsole(game);
				al_flip_display();
#ifdef __EMSCRIPTEN__
				emscripten_sleep(0);
#endif

				tmp->loaded = true;
				tmp->pending_load = false;
			}
			if (tmp->show_loading && game->_priv.loading.gamestate->open) {
				(*game->_priv.loading.gamestate->api->stop)(game, game->_priv.loading.gamestate->data);
			}
			tmp->show_loading = true;
			game->loading.shown = false;
			game->_priv.timestamp = al_get_time();
#ifdef __EMSCRIPTEN__
			al_attach_mixer_to_voice(game->audio.mixer, game->audio.v);
#endif
		}

		tmp = tmp->next;
	}
Ejemplo n.º 20
0
void credits2(void)
{
    int i, ch;
    int p;
    int plast = -1;
    clrscr();

    centerprint(aa_imgwidth(context) / 2, aa_imgheight(context) / 3, 3, 128, "The", 0);
    centerprint(aa_imgwidth(context) / 2, 2 * aa_imgheight(context) / 3, 3, 128, "END", 0);
    drawptr = decrand;
    params->randomval = 50;
    timestuff(0, NULL, draw, 5000000);
    drawptr = NULL;
    params->randomval = 0;
    drawptr = pryc;
    timestuff(0, NULL, draw, MAXTIME);
    drawptr = NULL;
    clrscr();
    draw();
    load_song("bb3.s3m");
    bbupdate();
    starttime = endtime = TIME;
    play();
    bbwait(1);
    for (i = 0; i < LOGOHEIGHT; i++) {
	aa_puts(context, aa_scrwidth(context) / 2 - 2, LOGOY + i, AA_BOLD, "8  8");
	if (i)
	    aa_puts(context, aa_scrwidth(context) / 2 - 2, LOGOY + i - 1, AA_NORMAL, "8  8");
	bbflushwait(100000);
    }
    aa_puts(context, aa_scrwidth(context) / 2 - 2, LOGOY + i - 1, AA_NORMAL, "8  8");

#define LWIDTH

    for (i = aa_scrwidth(context) / 2; i; i--) {
	display8();
	displaya(i);
	bbflushwait(10000);
    }
    for (; i < 100; i++) {
	textclrscr();
	displaya(10 * sin(i * M_PI / 100));
	display8();
	bbflushwait(10000);
    }
    aa_puts(context, aa_scrwidth(context) / 2 - 9, LOGOY + 3, AA_DIM, "<PROJECT><PROJECT>");
    bbflushwait(100000);
    aa_puts(context, aa_scrwidth(context) / 2 - 9, LOGOY + 3, AA_NORMAL, "<PROJECT><PROJECT>");
    bbflushwait(100000);
    aa_puts(context, aa_scrwidth(context) / 2 - 9, LOGOY + 3, AA_BOLD, "<PROJECT><PROJECT>");
    bbflushwait(100000);
    aa_puts(context, aa_scrwidth(context) / 2 - 9, LOGOY + 3, AA_NORMAL, "<PROJECT><PROJECT>");
    bbflushwait(100000);
    bbwait(1000000);
    for (i = LOGOY; i > 1; i--) {
	textclrscr();
	displogo(i);
	bbflushwait(30000);
    }

    source = malloc(aa_imgwidth(context) * (aa_imgheight(context)));
    target = malloc(aa_imgwidth(context) * (aa_imgheight(context)));
    params->dither = AA_NONE;
    format(dual ? aa_scrwidth(context) / 2 : aa_scrwidth(context));
    p = 0;
    while (1) {
	if (p != plast) {
	    getsource();
	    displaytext(p);
	    gettarget();
	    morph();
	    displaytext(p);
	    aa_flush(context);
        emscripten_sleep(1);
	    plast = p;
	}
      again:
    emscripten_sleep(100);
#ifndef __DJGPP__
	//ch = aa_getkey(context, 100);
    ch = AA_NONE;
#else
	while ((ch = bbupdate()) == AA_NONE) ;
#endif

	switch (ch) {
	case '1':
	    load_song("bb.s3m");
	    bbupdate();
	    play();
	    break;
	case '2':
	    load_song("bb2.s3m");
	    bbupdate();
	    play();
	    break;
	case '3':
	    load_song("bb3.s3m");
	    bbupdate();
	    play();
	    break;

	case 'b':
	case 'k':
	case 'B':
	case 'K':
	case AA_BACKSPACE:
	case AA_UP:
	    p -= (aa_scrheight(context) - YSTART) / 2 * (dual + 1);
	    if (p < 0)
		p = 0;
	    break;
	case AA_DOWN:
	case AA_LEFT:
	case 'f':
	case 'F':
	case ' ':
	case 'j':
	case 'J':
	    p += (aa_scrheight(context) - YSTART) / 2 * (dual + 1);
	    if (p > textsize)
		p = textsize;
	    break;
	case 'q':
	case 'Q':
	case AA_ESC:
	    finish_stuff = 0;
	    backconvert(0, 0, aa_scrwidth(context), aa_scrheight(context));
	    bbupdate();
	    starttime = endtime = TIME;
	    drawptr = decbright;
	    timestuff(0, NULL, draw, 1000000);
	    textclrscr();
	    drawptr = NULL;
	    aa_flush(context);
        emscripten_sleep(1);
	    free(source);
	    free(target);
	    return;
	default:
	    goto again;
	}
	bbupdate();
	starttime = endtime = TIME;
    }
}