コード例 #1
0
ファイル: page.c プロジェクト: HybridDog/schismtracker
static void _mp_change(void)
{
	if (_mp_setv) _mp_setv(_mpw[0].d.thumbbar.value);
	if (!(song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP))) {
		if (_mp_setv_noplay)
			_mp_setv_noplay(_mpw[0].d.thumbbar.value);
	}
	_mp_active = 2;
}
コード例 #2
0
ファイル: page.c プロジェクト: HybridDog/schismtracker
static inline void draw_time(void)
{
	char buf[16];
	int is_playing = song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP);

	if (status.time_display == TIME_OFF || (status.time_display == TIME_PLAY_OFF && !is_playing))
		return;

	/* this allows for 999 hours... that's like... 41 days...
	 * who on earth leaves a tracker running for 41 days? */
	sprintf(buf, "%3d:%02d:%02d", current_time.h % 1000,
		current_time.m % 60, current_time.s % 60);
	draw_text(buf, 69, 9, 0, 2);
}
コード例 #3
0
/* this does the lines for playing samples */
static void _draw_sample_play_marks(struct vgamem_overlay *r, song_sample_t * sample)
{
        int n, x, y;
        int c;
        song_voice_t *channel;
        unsigned int *channel_list;

        if (song_get_mode() == MODE_STOPPED)
                return;

        song_lock_audio();

        n = song_get_mix_state(&channel_list);
        while (n--) {
                channel = song_get_mix_channel(channel_list[n]);
                if (channel->current_sample_data != sample->data)
                        continue;
                if (!channel->final_volume) continue;
                c = (channel->flags & (CHN_KEYOFF | CHN_NOTEFADE)) ? SAMPLE_BGMARK_COLOR : SAMPLE_MARK_COLOR;
                x = channel->position * (r->width - 1) / sample->length;
                if (x >= r->width) {
                        /* this does, in fact, happen :( */
                        continue;
                }
                y = 0;
                do {
                        /* unrolled 8 times */
                        vgamem_ovl_drawpixel(r, x, y++, c);
                        vgamem_ovl_drawpixel(r, x, y++, c);
                        vgamem_ovl_drawpixel(r, x, y++, c);
                        vgamem_ovl_drawpixel(r, x, y++, c);
                        vgamem_ovl_drawpixel(r, x, y++, c);
                        vgamem_ovl_drawpixel(r, x, y++, c);
                        vgamem_ovl_drawpixel(r, x, y++, c);
                        vgamem_ovl_drawpixel(r, x, y++, c);
                } while (y < r->height);
        }

        song_unlock_audio();
}
コード例 #4
0
ファイル: page.c プロジェクト: HybridDog/schismtracker
/* return 1 -> the time changed; need to redraw */
static int check_time(void)
{
	static int last_o = -1, last_r = -1, last_timep = -1;

	time_t timep = 0;
	int h, m, s;
	enum tracker_time_display td = status.time_display;
	int is_playing = song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP);

	int row, order;

	switch (td) {
	case TIME_PLAY_ELAPSED:
		td = (is_playing ? TIME_PLAYBACK : TIME_ELAPSED);
		break;
	case TIME_PLAY_CLOCK:
		td = (is_playing ? TIME_PLAYBACK : TIME_CLOCK);
		break;
	case TIME_PLAY_OFF:
		td = (is_playing ? TIME_PLAYBACK : TIME_OFF);
		break;
	default:
		break;
	}

	switch (td) {
	case TIME_OFF:
		h = m = s = 0;
		break;
	case TIME_PLAYBACK:
		h = (m = (s = song_get_current_time()) / 60) / 60;
		break;
	case TIME_ELAPSED:
		h = (m = (s = SDL_GetTicks() / 1000) / 60) / 60;
		break;
	case TIME_ABSOLUTE:
		/* absolute time shows the time of the current cursor
		position in the pattern editor :) */
		if (status.current_page == PAGE_PATTERN_EDITOR) {
			row = get_current_row();
			order = song_next_order_for_pattern(get_current_pattern());
		} else {
			order = get_current_order();
			row = 0;
		}
		if (order < 0) {
			s = m = h = 0;
		} else {
			if (last_o == order && last_r == row) {
				timep = last_timep;
			} else {
				last_timep = timep = song_get_length_to(order, row);
				last_o = order;
				last_r = row;
			}
			s = timep % 60;
			m = (timep / 60) % 60;
			h = (timep / 3600);
		}
		break;
	default:
		/* this will never happen */
	case TIME_CLOCK:
		/* Impulse Tracker doesn't have this, but I always wanted it, so here 'tis. */
		h = status.tmnow.tm_hour;
		m = status.tmnow.tm_min;
		s = status.tmnow.tm_sec;
		break;
	}

	if (h == current_time.h && m == current_time.m && s == current_time.s) {
		return 0;
	}

	current_time.h = h;
	current_time.m = m;
	current_time.s = s;
	return 1;
}
コード例 #5
0
ファイル: page.c プロジェクト: HybridDog/schismtracker
/* returns 1 if the key was handled */
static int handle_key_global(struct key_event * k)
{
	int i, ins_mode;

	if (_mp_active == 2 && (k->mouse == MOUSE_CLICK && k->state == KEY_RELEASE)) {
		status.flags |= NEED_UPDATE;
		dialog_destroy_all();
		_mp_active = 0;
		// eat it...
		return 1;
	}
	if ((!_mp_active) && k->state == KEY_PRESS && k->mouse == MOUSE_CLICK) {
		if (k->x >= 63 && k->x <= 77 && k->y >= 6 && k->y <= 7) {
			status.vis_style++;
			status.vis_style %= VIS_SENTINEL;
			status.flags |= NEED_UPDATE;
			return 1;
		} else if (k->y == 5 && k->x == 50) {
			minipop_slide(kbd_get_current_octave(), "Octave", 0, 8,
				kbd_set_current_octave, NULL, 50, 5);
			return 1;
		} else if (k->y == 4 && k->x >= 50 && k->x <= 52) {
			minipop_slide(song_get_current_speed(), "Speed", 1, 255,
				song_set_current_speed, song_set_initial_speed, 51, 4);
			return 1;
		} else if (k->y == 4 && k->x >= 54 && k->x <= 56) {
			minipop_slide(song_get_current_tempo(), "Tempo", 32, 255,
				song_set_current_tempo, song_set_initial_tempo, 55, 4);
			return 1;
		} else if (k->y == 3 && k->x >= 50 && k-> x <= 77) {
			if (page_is_instrument_list(status.current_page)
			    || status.current_page == PAGE_SAMPLE_LIST
			    || (!(status.flags & CLASSIC_MODE)
				&& (status.current_page == PAGE_ORDERLIST_PANNING
				    || status.current_page == PAGE_ORDERLIST_VOLUMES)))
				ins_mode = 0;
			else
				ins_mode = song_is_instrument_mode();
			if (ins_mode) {
				minipop_slide(instrument_get_current(), "!",
					status.current_page == PAGE_INSTRUMENT_LIST ? 1 : 0,
					99 /* FIXME */, instrument_set, NULL, 58, 3);
			} else {
				minipop_slide(sample_get_current(), "@",
					status.current_page == PAGE_SAMPLE_LIST ? 1 : 0,
					99 /* FIXME */, sample_set, NULL, 58, 3);
			}

		} else if (k->y == 7 && k->x >= 11 && k->x <= 17) {
			minipop_slide(get_current_row(), "Row",
				0, song_get_rows_in_pattern(get_current_pattern()),
				set_current_row, NULL, 14, 7);
			return 1;
		} else if (k->y == 6 && k->x >= 11 && k->x <= 17) {
			minipop_slide(get_current_pattern(), "Pattern",
				0, csf_get_num_patterns(current_song),
				set_current_pattern, NULL, 14, 6);
			return 1;
		} else if (k->y == 5 && k->x >= 11 && k->x <= 17) {
			minipop_slide(song_get_current_order(), "Order",
				0, csf_get_num_orders(current_song),
				set_current_order, NULL, 14, 5);
			return 1;
		}
	} else if ((!_mp_active) && k->mouse == MOUSE_DBLCLICK) {
		if (k->y == 4 && k->x >= 11 && k->x <= 28) {
			set_page(PAGE_SAVE_MODULE);
			return 1;
		} else if (k->y == 3 && k->x >= 11 && k->x <= 35) {
			set_page(PAGE_SONG_VARIABLES);
			return 1;
		}
	}

	/* shortcut */
	if (k->mouse != MOUSE_NONE) {
		return 0;
	}

	/* first, check the truly global keys (the ones that still work if
	 * a dialog's open) */
	switch (k->sym) {
	case SDLK_RETURN:
		if ((k->mod & KMOD_CTRL) && k->mod & KMOD_ALT) {
			if (k->state == KEY_PRESS)
				return 1;
			toggle_display_fullscreen();
			return 1;
		}
		break;
	case SDLK_m:
		if (k->mod & KMOD_CTRL) {
			if (k->state == KEY_RELEASE)
				return 1;
			video_mousecursor(MOUSE_CYCLE_STATE);
			return 1;
		}
		break;

	case SDLK_d:
		if (k->mod & KMOD_CTRL) {
			if (k->state == KEY_RELEASE)
				return 1; /* argh */
			i = SDL_WM_GrabInput(SDL_GRAB_QUERY);
			if (i == SDL_GRAB_QUERY)
				i = currently_grabbed;
			currently_grabbed = i = (i != SDL_GRAB_ON ? SDL_GRAB_ON : SDL_GRAB_OFF);
			SDL_WM_GrabInput(i);
			status_text_flash(i
				? "Mouse and keyboard grabbed, press Ctrl+D to release"
				: "Mouse and keyboard released");
			return 1;
		}
		break;

	case SDLK_i:
		/* reset audio stuff? */
		if (k->mod & KMOD_CTRL) {
			if (k->state == KEY_RELEASE)
				return 1;
			audio_reinit();
			return 1;
		}
		break;
	case SDLK_e:
		/* This should reset everything display-related. */
		if (k->mod & KMOD_CTRL) {
			if (k->state == KEY_RELEASE)
				return 1;
			font_init();
			status.flags |= NEED_UPDATE;
			return 1;
		}
		break;
	case SDLK_HOME:
		if (!(k->mod & KMOD_ALT)) break;
		if (status.flags & DISKWRITER_ACTIVE) break;
		if (k->state == KEY_RELEASE)
			return 0;
		kbd_set_current_octave(kbd_get_current_octave() - 1);
		return 1;
	case SDLK_END:
		if (!(k->mod & KMOD_ALT)) break;
		if (status.flags & DISKWRITER_ACTIVE) break;
		if (k->state == KEY_RELEASE)
			return 0;
		kbd_set_current_octave(kbd_get_current_octave() + 1);
		return 1;
	default:
		break;
	}

	/* next, if there's no dialog, check the rest of the keys */
	if (status.flags & DISKWRITER_ACTIVE) return 0;

	switch (k->sym) {
	case SDLK_q:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				show_exit_prompt();
			return 1;
		}
		break;
	case SDLK_n:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				new_song_dialog();
			return 1;
		}
		break;
	case SDLK_g:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				show_song_timejump();
			return 1;
		}
		break;
	case SDLK_p:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				show_song_length();
			return 1;
		}
		break;
	case SDLK_F1:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_CONFIG);
		} else if (k->mod & KMOD_SHIFT) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(status.current_page == PAGE_MIDI ? PAGE_MIDI_OUTPUT : PAGE_MIDI);
		} else if (NO_MODIFIER(k->mod)) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_HELP);
		} else {
			break;
		}
		return 1;
	case SDLK_F2:
		if (k->mod & KMOD_CTRL) {
			if (status.current_page == PAGE_PATTERN_EDITOR) {
				_mp_finish(NULL);
				if (k->state == KEY_PRESS && status.dialog_type == DIALOG_NONE) {
					pattern_editor_length_edit();
				}
				return 1;
			}
			if (status.dialog_type != DIALOG_NONE)
				return 0;
		} else if (NO_MODIFIER(k->mod)) {
			if (status.current_page == PAGE_PATTERN_EDITOR) {
				if (k->state == KEY_PRESS) {
					if (status.dialog_type & DIALOG_MENU) {
						return 0;
					} else if (status.dialog_type != DIALOG_NONE) {
						dialog_yes_NULL();
						status.flags |= NEED_UPDATE;
					} else {
						_mp_finish(NULL);
						pattern_editor_display_options();
					}
				}
			} else {
				if (status.dialog_type != DIALOG_NONE)
					return 0;
				_mp_finish(NULL);
				if (k->state == KEY_PRESS)
					set_page(PAGE_PATTERN_EDITOR);
			}
			return 1;
		}
		break;
	case SDLK_F3:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (NO_MODIFIER(k->mod)) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_SAMPLE_LIST);
		} else {
			_mp_finish(NULL);
			if (k->mod & KMOD_CTRL) set_page(PAGE_LIBRARY_SAMPLE);
			break;
		}
		return 1;
	case SDLK_F4:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (NO_MODIFIER(k->mod)) {
			if (status.current_page == PAGE_INSTRUMENT_LIST) return 0;
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_INSTRUMENT_LIST);
		} else {
			if (k->mod & KMOD_SHIFT) return 0;
			_mp_finish(NULL);
			if (k->mod & KMOD_CTRL) set_page(PAGE_LIBRARY_INSTRUMENT);
			break;
		}
		return 1;
	case SDLK_F5:
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				song_start();
		} else if (k->mod & KMOD_SHIFT) {
			if (status.dialog_type != DIALOG_NONE)
				return 0;
			_mp_finish(NULL);
			if (k->state == KEY_RELEASE)
				set_page(PAGE_PREFERENCES);
		} else if (NO_MODIFIER(k->mod)) {
			if (song_get_mode() == MODE_STOPPED
			|| (song_get_mode() == MODE_SINGLE_STEP && status.current_page == PAGE_INFO)) {
				_mp_finish(NULL);
				if (k->state == KEY_PRESS)
					song_start();
			}
			if (k->state == KEY_PRESS) {
				if (status.dialog_type != DIALOG_NONE)
					return 0;
				_mp_finish(NULL);
				set_page(PAGE_INFO);
			}
		} else {
			break;
		}
		return 1;
	case SDLK_F6:
		if (k->mod & KMOD_SHIFT) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				song_start_at_order(get_current_order(), 0);
		} else if (NO_MODIFIER(k->mod)) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				song_loop_pattern(get_current_pattern(), 0);
		} else {
			break;
		}
		return 1;
	case SDLK_F7:
		if (NO_MODIFIER(k->mod)) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				play_song_from_mark();
		} else {
			break;
		}
		return 1;
	case SDLK_F8:
		if (k->mod & KMOD_SHIFT) {
			if (k->state == KEY_PRESS)
				song_pause();
		} else if (NO_MODIFIER(k->mod)) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				song_stop();
			status.flags |= NEED_UPDATE;
		} else {
			break;
		}
		return 1;
	case SDLK_F9:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_SHIFT) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_MESSAGE);
		} else if (NO_MODIFIER(k->mod)) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_LOAD_MODULE);
		} else {
			break;
		}
		return 1;
	case SDLK_l:
	case SDLK_r:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_RELEASE)
				set_page(PAGE_LOAD_MODULE);
		} else {
			break;
		}
		return 1;
	case SDLK_s:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_RELEASE)
				save_song_or_save_as();
		} else {
			break;
		}
		return 1;
	case SDLK_w:
		/* Ctrl-W _IS_ in IT, and hands don't leave home row :) */
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_RELEASE)
				set_page(PAGE_SAVE_MODULE);
		} else {
			break;
		}
		return 1;
	case SDLK_F10:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (k->mod & KMOD_ALT) break;
		if (k->mod & KMOD_CTRL) break;

		_mp_finish(NULL);
		if (k->mod & KMOD_SHIFT) {
			if (k->state == KEY_PRESS)
				set_page(PAGE_EXPORT_MODULE);
		} else {
			if (k->state == KEY_PRESS)
				set_page(PAGE_SAVE_MODULE);
		}
		return 1;
	case SDLK_F11:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if (NO_MODIFIER(k->mod)) {
			_mp_finish(NULL);
			if (status.current_page == PAGE_ORDERLIST_PANNING) {
				if (k->state == KEY_PRESS)
					set_page(PAGE_ORDERLIST_VOLUMES);
			} else {
				if (k->state == KEY_PRESS)
					set_page(PAGE_ORDERLIST_PANNING);
			}
		} else if (k->mod & KMOD_CTRL) {
			if (k->state == KEY_PRESS) {
				_mp_finish(NULL);
				if (status.current_page == PAGE_LOG) {
					show_about();
				} else {
					set_page(PAGE_LOG);
				}
			}
		} else if (k->state == KEY_PRESS && (k->mod & KMOD_ALT)) {
			_mp_finish(NULL);
			if (song_toggle_orderlist_locked())
				status_text_flash("Order list locked");
			else
				status_text_flash("Order list unlocked");
		} else {
			break;
		}
		return 1;
	case SDLK_F12:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		if ((k->mod & KMOD_ALT) && status.current_page == PAGE_INFO) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_WATERFALL);
		} else if (k->mod & KMOD_CTRL) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_PALETTE_EDITOR);
		} else if (k->mod & KMOD_SHIFT) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS) {
				fontedit_return_page = status.current_page;
				set_page(PAGE_FONT_EDIT);
			}

		} else if (NO_MODIFIER(k->mod)) {
			_mp_finish(NULL);
			if (k->state == KEY_PRESS)
				set_page(PAGE_SONG_VARIABLES);
		} else {
			break;
		}
		return 1;
	/* hack alert */
	case SDLK_f:
		if (!(k->mod & KMOD_CTRL))
			return 0;
		/* fall through */
	case SDLK_SCROLLOCK:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		_mp_finish(NULL);
		if (k->mod & KMOD_ALT) {
			if (k->state == KEY_PRESS) {
				midi_flags ^= (MIDI_DISABLE_RECORD);
				status_text_flash("MIDI Input %s",
					(midi_flags & MIDI_DISABLE_RECORD)
					? "Disabled" : "Enabled");
			}
			return 1;
		} else {
			/* os x steals plain scroll lock for brightness,
			 * so catch ctrl+scroll lock here as well */
			if (k->state == KEY_PRESS) {
				midi_playback_tracing = (playback_tracing = !playback_tracing);
				status_text_flash("Playback tracing %s",
						  (playback_tracing ? "enabled" : "disabled"));
			}
			return 1;
		}
	default:
		if (status.dialog_type != DIALOG_NONE)
			return 0;
		break;
	}

	/* got a bit ugly here, sorry */
	i = k->sym;
	if (k->mod & KMOD_ALT) {
		switch (i) {
		case SDLK_F1: i = 0; break;
		case SDLK_F2: i = 1; break;
		case SDLK_F3: i = 2; break;
		case SDLK_F4: i = 3; break;
		case SDLK_F5: i = 4; break;
		case SDLK_F6: i = 5; break;
		case SDLK_F7: i = 6; break;
		case SDLK_F8: i = 7; break;
		default:
			return 0;
		};
		if (k->state == KEY_RELEASE)
			return 1;

		song_toggle_channel_mute(i);
		status.flags |= NEED_UPDATE;
		return 1;
	}

	/* oh well */
	return 0;
}
コード例 #6
0
ファイル: page.c プロジェクト: HybridDog/schismtracker
/* this is the important one */
void handle_key(struct key_event *k)
{
	if (_handle_ime(k))
		return;

	/* okay... */
	if (!(status.flags & DISKWRITER_ACTIVE) && ACTIVE_PAGE.pre_handle_key) {
		if (ACTIVE_PAGE.pre_handle_key(k)) return;
	}

	if (handle_key_global(k)) return;
	if (!(status.flags & DISKWRITER_ACTIVE) && menu_handle_key(k)) return;
	if (widget_handle_key(k)) return;

	/* now check a couple other keys. */
	switch (k->sym) {
	case SDLK_LEFT:
		if (k->state == KEY_RELEASE) return;
		if (status.flags & DISKWRITER_ACTIVE) return;
		if ((k->mod & KMOD_CTRL) && status.current_page != PAGE_PATTERN_EDITOR) {
			_mp_finish(NULL);
			if (song_get_mode() == MODE_PLAYING)
				song_set_current_order(song_get_current_order() - 1);
			return;
		}
		break;
	case SDLK_RIGHT:
		if (k->state == KEY_RELEASE) return;
		if (status.flags & DISKWRITER_ACTIVE) return;
		if ((k->mod & KMOD_CTRL) && status.current_page != PAGE_PATTERN_EDITOR) {
			_mp_finish(NULL);
			if (song_get_mode() == MODE_PLAYING)
				song_set_current_order(song_get_current_order() + 1);
			return;
		}
		break;
	case SDLK_ESCAPE:
		/* TODO | Page key handlers should return true/false depending on if the key was handled
		   TODO | (same as with other handlers), and the escape key check should go *after* the
		   TODO | page gets a chance to grab it. This way, the load sample page can switch back
		   TODO | to the sample list on escape like it's supposed to. (The status.current_page
		   TODO | checks above won't be necessary, either.) */
		if (NO_MODIFIER(k->mod) && status.dialog_type == DIALOG_NONE
		    && status.current_page != PAGE_LOAD_SAMPLE
		    && status.current_page != PAGE_LOAD_INSTRUMENT) {
			if (k->state == KEY_RELEASE) return;
			if (_mp_active) {
				_mp_finish(NULL);
				return;
			}
			menu_show();
			return;
		}
		break;
	case SDLK_SLASH:
		if (k->state == KEY_RELEASE) return;
		if (status.flags & DISKWRITER_ACTIVE) return;
		if (k->orig_sym == SDLK_KP_DIVIDE) {
			kbd_set_current_octave(kbd_get_current_octave() - 1);
		}
		return;
	case SDLK_ASTERISK:
		if (k->state == KEY_RELEASE) return;
		if (status.flags & DISKWRITER_ACTIVE) return;
		if (k->orig_sym == SDLK_KP_MULTIPLY) {
			kbd_set_current_octave(kbd_get_current_octave() + 1);
		}
		return;
	case SDLK_LEFTBRACKET:
		if (k->state == KEY_RELEASE) break;
		if (status.flags & DISKWRITER_ACTIVE) return;
		if (k->mod & KMOD_SHIFT) {
			song_set_current_speed(song_get_current_speed() - 1);
			status_text_flash("Speed set to %d frames per row", song_get_current_speed());
			if (!(song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP))) {
				song_set_initial_speed(song_get_current_speed());
			}
		} else if ((k->mod & KMOD_CTRL) && !(status.flags & CLASSIC_MODE)) {
			song_set_current_tempo(song_get_current_tempo() - 1);
			status_text_flash("Tempo set to %d frames per row", song_get_current_tempo());
			if (!(song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP))) {
				song_set_initial_tempo(song_get_current_tempo());
			}
		} else if (NO_MODIFIER(k->mod)) {
			song_set_current_global_volume(song_get_current_global_volume() - 1);
			status_text_flash("Global volume set to %d", song_get_current_global_volume());
			if (!(song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP))) {
				song_set_initial_global_volume(song_get_current_global_volume());
			}
		}
		return;
	case SDLK_RIGHTBRACKET:
		if (k->state == KEY_RELEASE) break;
		if (status.flags & DISKWRITER_ACTIVE) return;
		if (k->mod & KMOD_SHIFT) {
			song_set_current_speed(song_get_current_speed() + 1);
			status_text_flash("Speed set to %d frames per row", song_get_current_speed());
			if (!(song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP))) {
				song_set_initial_speed(song_get_current_speed());
			}
		} else if ((k->mod & KMOD_CTRL) && !(status.flags & CLASSIC_MODE)) {
			song_set_current_tempo(song_get_current_tempo() + 1);
			status_text_flash("Tempo set to %d frames per row", song_get_current_tempo());
			if (!(song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP))) {
				song_set_initial_tempo(song_get_current_tempo());
			}
		} else if (NO_MODIFIER(k->mod)) {
			song_set_current_global_volume(song_get_current_global_volume() + 1);
			status_text_flash("Global volume set to %d", song_get_current_global_volume());
			if (!(song_get_mode() & (MODE_PLAYING | MODE_PATTERN_LOOP))) {
				song_set_initial_global_volume(song_get_current_global_volume());
			}
		}
		return;

	default:
		break;
	}

	/* and if we STILL didn't handle the key, pass it to the page.
	 * (or dialog, if one's active) */
	if (status.dialog_type & DIALOG_BOX) {
		dialog_handle_key(k);
	} else {
		if (status.flags & DISKWRITER_ACTIVE) return;
		if (ACTIVE_PAGE.handle_key) ACTIVE_PAGE.handle_key(k);
	}
}