diff --git a/apps/action.c b/apps/action.c index aa19403703..15b2d8a4c8 100644 --- a/apps/action.c +++ b/apps/action.c @@ -203,9 +203,7 @@ static int get_action_worker(int context, int timeout, #if CONFIG_CODEC == SWCODEC /* Produce keyclick */ - if (global_settings.keyclick && !(button & BUTTON_REL)) - if (!(button & BUTTON_REPEAT) || global_settings.keyclick_repeats) - beep_play(4000, KEYCLICK_DURATION, 2500*global_settings.keyclick); + keyclick_click(button); #endif if ((context != last_context) && ((last_button & BUTTON_REL) == 0) diff --git a/apps/gui/wps.c b/apps/gui/wps.c index cbf003adbd..80522d04bd 100644 --- a/apps/gui/wps.c +++ b/apps/gui/wps.c @@ -577,8 +577,7 @@ static void play_hop(int direction) else if (direction == 1 && step >= remaining) { #if CONFIG_CODEC == SWCODEC - if(global_settings.beep) - beep_play(1000, 150, 1500*global_settings.beep); + system_sound_play(SOUND_TRACK_NO_MORE); #endif return; } diff --git a/apps/misc.c b/apps/misc.c index dfee05fb5a..1800342a50 100644 --- a/apps/misc.c +++ b/apps/misc.c @@ -1037,3 +1037,51 @@ enum current_activity get_current_activity(void) return current_activity[current_activity_top?current_activity_top-1:0]; } +#if CONFIG_CODEC == SWCODEC +/* Play a standard sound */ +void system_sound_play(enum system_sound sound) +{ + static const struct beep_params + { + int *setting; + unsigned short frequency; + unsigned short duration; + unsigned short amplitude; + } beep_params[] = + { + [SOUND_KEYCLICK] = + { &global_settings.keyclick, + 4000, KEYCLICK_DURATION, 2500 }, + [SOUND_TRACK_SKIP] = + { &global_settings.beep, + 2000, 100, 2500 }, + [SOUND_TRACK_NO_MORE] = + { &global_settings.beep, + 1000, 100, 1500 }, + }; + + const struct beep_params *params = &beep_params[sound]; + + if (*params->setting) + { + beep_play(params->frequency, params->duration, + params->amplitude * *params->setting); + } +} + +/* Produce keyclick based upon button and global settings */ +void keyclick_click(int button) +{ + /* Settings filters */ + if (global_settings.keyclick && + (global_settings.keyclick_repeats || !(button & BUTTON_REPEAT))) + { + /* Button filters */ + if (button != BUTTON_NONE && !(button & BUTTON_REL) + && !(button & (SYS_EVENT|BUTTON_MULTIMEDIA)) ) + { + system_sound_play(SOUND_KEYCLICK); + } + } +} +#endif /* CONFIG_CODEC == SWCODEC */ diff --git a/apps/misc.h b/apps/misc.h index c3c52d13e0..7ea5360db5 100644 --- a/apps/misc.h +++ b/apps/misc.h @@ -100,9 +100,6 @@ int clamp_value_wrap(int value, int max, int min); #endif #endif -void beep_play(unsigned int frequency, unsigned int duration, - unsigned int amplitude); - enum current_activity { ACTIVITY_UNKNOWN = 0, ACTIVITY_MAINMENU, @@ -118,6 +115,25 @@ enum current_activity { ACTIVITY_PITCHSCREEN, ACTIVITY_OPTIONSELECT }; + +#if CONFIG_CODEC == SWCODEC +void beep_play(unsigned int frequency, unsigned int duration, + unsigned int amplitude); + +enum system_sound +{ + SOUND_KEYCLICK = 0, + SOUND_TRACK_SKIP, + SOUND_TRACK_NO_MORE, +}; + +/* Play a standard sound */ +void system_sound_play(enum system_sound sound); + +/* Produce keyclick based upon button and global settings */ +void keyclick_click(int button); +#endif /* CONFIG_CODEC == SWCODEC */ + void push_current_activity(enum current_activity screen); void pop_current_activity(void); enum current_activity get_current_activity(void); diff --git a/apps/playback.c b/apps/playback.c index cbb94a9d22..c74c606016 100644 --- a/apps/playback.c +++ b/apps/playback.c @@ -3352,8 +3352,7 @@ void audio_skip(int offset) processed one */ skip_offset = accum; - if (global_settings.beep) - beep_play(2000, 100, 2500*global_settings.beep); + system_sound_play(SOUND_TRACK_SKIP); LOGFQUEUE("audio > audio Q_AUDIO_SKIP %d", offset); @@ -3373,8 +3372,7 @@ void audio_skip(int offset) else { /* No more tracks */ - if (global_settings.beep) - beep_play(1000, 100, 1500*global_settings.beep); + system_sound_play(SOUND_TRACK_NO_MORE); } id3_mutex_unlock(); diff --git a/apps/plugin.c b/apps/plugin.c index 6b3d39973f..b47dd951ea 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -782,6 +782,13 @@ static const struct plugin_api rockbox_api = { mixer_channel_status, mixer_channel_get_buffer, mixer_channel_calculate_peaks, + mixer_channel_play_data, + mixer_channel_play_pause, + mixer_channel_stop, + mixer_channel_set_amplitude, + mixer_channel_get_bytes_waiting, + system_sound_play, + keyclick_click, #endif }; diff --git a/apps/plugin.h b/apps/plugin.h index 77c8e831d4..e9c0c64a00 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -146,7 +146,7 @@ void* plugin_get_buffer(size_t *buffer_size); #define PLUGIN_MAGIC 0x526F634B /* RocK */ /* increase this every time the api struct changes */ -#define PLUGIN_API_VERSION 207 +#define PLUGIN_API_VERSION 208 /* update this to latest version if a change to the api struct breaks backwards compatibility (and please take the opportunity to sort in any @@ -913,6 +913,16 @@ struct plugin_api { void * (*mixer_channel_get_buffer)(enum pcm_mixer_channel channel, int *count); void (*mixer_channel_calculate_peaks)(enum pcm_mixer_channel channel, int *left, int *right); + void (*mixer_channel_play_data)(enum pcm_mixer_channel channel, + pcm_play_callback_type get_more, + unsigned char *start, size_t size); + void (*mixer_channel_play_pause)(enum pcm_mixer_channel channel, bool play); + void (*mixer_channel_stop)(enum pcm_mixer_channel channel); + void (*mixer_channel_set_amplitude)(enum pcm_mixer_channel channel, + unsigned int amplitude); + size_t (*mixer_channel_get_bytes_waiting)(enum pcm_mixer_channel channel); + void (*system_sound_play)(enum system_sound sound); + void (*keyclick_click)(int button); #endif }; diff --git a/apps/plugins/mpegplayer/mpeg_misc.c b/apps/plugins/mpegplayer/mpeg_misc.c index d9e033322e..895fbe04a9 100644 --- a/apps/plugins/mpegplayer/mpeg_misc.c +++ b/apps/plugins/mpegplayer/mpeg_misc.c @@ -214,6 +214,10 @@ int mpeg_button_get(int timeout) mpeg_sysevent_clear(); button = timeout == TIMEOUT_BLOCK ? rb->button_get(true) : rb->button_get_w_tmo(timeout); + + /* Produce keyclick */ + rb->keyclick_click(button); + return mpeg_sysevent_callback(button, NULL); } diff --git a/apps/plugins/mpegplayer/mpegplayer.c b/apps/plugins/mpegplayer/mpegplayer.c index 41f6b2e868..c6e1f4dded 100644 --- a/apps/plugins/mpegplayer/mpegplayer.c +++ b/apps/plugins/mpegplayer/mpegplayer.c @@ -386,6 +386,7 @@ enum video_action VIDEO_STOP = 0, VIDEO_PREV, VIDEO_NEXT, + VIDEO_ACTION_MANUAL = 0x8000, /* Flag that says user did it */ }; /* OSD status - same order as icon array */ @@ -2139,7 +2140,7 @@ static int button_loop(void) /* Release within 3 seconds of start: skip to previous * file */ osd_stop(); - next_action = VIDEO_PREV; + next_action = VIDEO_PREV | VIDEO_ACTION_MANUAL; } } else if ((button & ~BUTTON_REPEAT) == old_button) { @@ -2169,7 +2170,7 @@ static int button_loop(void) if ((old_button | BUTTON_REL) == button) { /* If button has been released: skip to next file */ osd_stop(); - next_action = VIDEO_NEXT; + next_action = VIDEO_NEXT | VIDEO_ACTION_MANUAL; } else if ((button & ~BUTTON_REPEAT) == old_button) { button = osd_seek_btn(old_button); @@ -2251,11 +2252,10 @@ enum plugin_status plugin_start(const void* parameter) while (!quit) { - int result; - init_settings(videofile); - result = stream_open(videofile); + int result = stream_open(videofile); + bool manual_skip = false; if (result >= STREAM_OK) { /* start menu */ @@ -2267,6 +2267,8 @@ enum plugin_status plugin_start(const void* parameter) if (result != MPEG_START_QUIT) { /* Enter button loop and process UI */ next_action = button_loop(); + manual_skip = next_action & VIDEO_ACTION_MANUAL; + next_action &= ~VIDEO_ACTION_MANUAL; } stream_close(); @@ -2341,6 +2343,13 @@ enum plugin_status plugin_start(const void* parameter) sizeof(videofile)); /* quit after finished the last videofile */ quit = !get_videofile_says; + + if (manual_skip) + { + rb->system_sound_play(get_videofile_says ? + SOUND_TRACK_SKIP : SOUND_TRACK_NO_MORE); + } + break; } case VIDEO_PREV: @@ -2348,6 +2357,13 @@ enum plugin_status plugin_start(const void* parameter) get_videofile_says = get_videofile(VIDEO_PREV, videofile, sizeof(videofile)); /* if there is no previous file, play the same videofile */ + + if (manual_skip) + { + rb->system_sound_play(get_videofile_says ? + SOUND_TRACK_SKIP : SOUND_TRACK_NO_MORE); + } + break; } case VIDEO_STOP: diff --git a/apps/plugins/mpegplayer/pcm_output.c b/apps/plugins/mpegplayer/pcm_output.c index fb7ff434aa..8db9531049 100644 --- a/apps/plugins/mpegplayer/pcm_output.c +++ b/apps/plugins/mpegplayer/pcm_output.c @@ -23,6 +23,9 @@ #include "plugin.h" #include "mpegplayer.h" +/* PCM channel we're using */ +#define MPEG_PCM_CHANNEL PCM_MIXER_CHAN_PLAYBACK + /* Pointers */ /* Start of buffer */ @@ -217,24 +220,22 @@ bool pcm_output_empty(void) /* Flushes the buffer - clock keeps counting */ void pcm_output_flush(void) { - bool playing, paused; - rb->pcm_play_lock(); - playing = rb->pcm_is_playing(); - paused = rb->pcm_is_paused(); + enum channel_status status = rb->mixer_channel_status(MPEG_PCM_CHANNEL); /* Stop PCM to clear current buffer */ - if (playing) - rb->pcm_play_stop(); + if (status != CHANNEL_STOPPED) + rb->mixer_channel_stop(MPEG_PCM_CHANNEL); + + rb->pcm_play_unlock(); pcm_reset_buffer(); /* Restart if playing state was current */ - if (playing && !paused) - rb->pcm_play_data(get_more, NULL, 0); - - rb->pcm_play_unlock(); + if (status == CHANNEL_PLAYING) + rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, + get_more, NULL, 0); } /* Seek the reference clock to the specified time - next audio data ready to @@ -264,10 +265,12 @@ uint32_t pcm_output_get_clock(void) do { time = clock_time; - rem = rb->pcm_get_bytes_waiting() >> 2; + rem = rb->mixer_channel_get_bytes_waiting(MPEG_PCM_CHANNEL) >> 2; } while (UNLIKELY(time != clock_time || - (rem == 0 && rb->pcm_is_playing() && !rb->pcm_is_paused()))); + (rem == 0 && + rb->mixer_channel_status(MPEG_PCM_CHANNEL) == CHANNEL_PLAYING)) + ); return time - rem; @@ -283,10 +286,12 @@ uint32_t pcm_output_get_ticks(uint32_t *start) do { tick = clock_tick; - rem = rb->pcm_get_bytes_waiting() >> 2; + rem = rb->mixer_channel_get_bytes_waiting(MPEG_PCM_CHANNEL) >> 2; } while (UNLIKELY(tick != clock_tick || - (rem == 0 && rb->pcm_is_playing() && !rb->pcm_is_paused()))); + (rem == 0 && + rb->mixer_channel_status(MPEG_PCM_CHANNEL) == CHANNEL_PLAYING)) + ); if (start) *start = clock_start; @@ -299,16 +304,22 @@ void pcm_output_play_pause(bool play) { rb->pcm_play_lock(); - if (rb->pcm_is_playing()) + if (rb->mixer_channel_status(MPEG_PCM_CHANNEL) != CHANNEL_STOPPED) { - rb->pcm_play_pause(play); + rb->mixer_channel_play_pause(MPEG_PCM_CHANNEL, play); + rb->pcm_play_unlock(); } - else if (play) + else { - rb->pcm_play_data(get_more, NULL, 0); - } + rb->pcm_play_unlock(); - rb->pcm_play_unlock(); + if (play) + { + rb->mixer_channel_set_amplitude(MPEG_PCM_CHANNEL, MIX_AMP_UNITY); + rb->mixer_channel_play_data(MPEG_PCM_CHANNEL, + get_more, NULL, 0); + } + } } /* Stops all playback and resets the clock */ @@ -316,13 +327,13 @@ void pcm_output_stop(void) { rb->pcm_play_lock(); - if (rb->pcm_is_playing()) - rb->pcm_play_stop(); + if (rb->mixer_channel_status(MPEG_PCM_CHANNEL) != CHANNEL_STOPPED) + rb->mixer_channel_stop(MPEG_PCM_CHANNEL); + + rb->pcm_play_unlock(); pcm_output_flush(); pcm_output_set_clock(0); - - rb->pcm_play_unlock(); } /* Drains any data if the start threshold hasn't been reached */ @@ -343,11 +354,6 @@ bool pcm_output_init(void) pcm_reset_buffer(); - /* Some targets could play at the movie frequency without resampling but - * as of now DSP assumes a certain frequency (always 44100Hz) so - * resampling will be needed for other movie audio rates. */ - rb->pcm_set_frequency(NATIVE_FREQUENCY); - #if INPUT_SRC_CAPS != 0 /* Select playback */ rb->audio_set_input_source(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); @@ -379,5 +385,4 @@ bool pcm_output_init(void) void pcm_output_exit(void) { - rb->pcm_set_frequency(HW_SAMPR_DEFAULT); }