summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorIgor B. Poretsky <poretsky@mlbox.ru>2017-12-19 01:06:53 +0300
committerSolomon Peachy <pizza@shaftnet.org>2020-08-07 03:44:13 +0000
commite0bcb0f2bc0fd57d4bea51c943fa4fb4388e34e4 (patch)
tree2aa6cb6dcd01a9aaf1636b7c672a515cde610b5f
parente0bb30a1bdf977765d1e891c1bc32bed3fa7c36e (diff)
downloadrockbox-e0bcb0f.tar.gz
rockbox-e0bcb0f.zip
Automatic choice of playback frequency by the playing file properties
Change-Id: I0fdc5d32225decbf051685be819be8df84171998
-rw-r--r--apps/playback.c83
-rw-r--r--apps/settings_list.c4
2 files changed, 78 insertions, 9 deletions
diff --git a/apps/playback.c b/apps/playback.c
index 2d9747e86a..504b3f4825 100644
--- a/apps/playback.c
+++ b/apps/playback.c
@@ -35,6 +35,9 @@
#include "talk.h"
#include "playlist.h"
#include "abrepeat.h"
+#ifdef HAVE_PLAY_FREQ
+#include "pcm_mixer.h"
+#endif
#include "pcmbuf.h"
#include "audio_thread.h"
#include "playback.h"
@@ -335,6 +338,7 @@ enum audio_start_playback_flags
{
AUDIO_START_RESTART = 0x1, /* "Restart" playback (flush _all_ tracks) */
AUDIO_START_NEWBUF = 0x2, /* Mark the audiobuffer as invalid */
+ AUDIO_START_REFRESH = 0x80
};
static void audio_start_playback(const struct audio_resume_info *resume_info,
@@ -2586,10 +2590,23 @@ static void audio_on_track_changed(void)
static void audio_start_playback(const struct audio_resume_info *resume_info,
unsigned int flags)
{
- struct audio_resume_info resume =
- *(resume_info ?: &(struct audio_resume_info){ 0, 0 } );
+ static struct audio_resume_info resume = { 0, 0 };
enum play_status old_status = play_status;
+ if (!(flags & AUDIO_START_REFRESH))
+ {
+ if (resume_info)
+ {
+ resume.elapsed = resume_info->elapsed;
+ resume.offset = resume_info->offset;
+ }
+ else
+ {
+ resume.elapsed = 0;
+ resume.offset = 0;
+ }
+ }
+
if (flags & AUDIO_START_NEWBUF)
{
/* Mark the buffer dirty - if not playing, it will be reset next
@@ -2613,8 +2630,13 @@ static void audio_start_playback(const struct audio_resume_info *resume_info,
/* Clear out some stuff to resume the current track where it
left off */
pcmbuf_play_stop();
- resume.elapsed = id3_get(PLAYING_ID3)->elapsed;
- resume.offset = id3_get(PLAYING_ID3)->offset;
+
+ if (!(flags & AUDIO_START_REFRESH))
+ {
+ resume.elapsed = id3_get(PLAYING_ID3)->elapsed;
+ resume.offset = id3_get(PLAYING_ID3)->offset;
+ }
+
track_list_clear(TRACK_LIST_CLEAR_ALL);
pcmbuf_update_frequency();
}
@@ -2629,6 +2651,7 @@ static void audio_start_playback(const struct audio_resume_info *resume_info,
pcmbuf_start_track_change(TRACK_CHANGE_MANUAL);
wipe_track_metadata(true);
}
+ pcmbuf_update_frequency();
/* Set after track finish event in case skip was in progress */
skip_pending = TRACK_SKIP_NONE;
@@ -3220,7 +3243,7 @@ void audio_playback_handler(struct queue_event *ev)
case Q_AUDIO_REMAKE_AUDIO_BUFFER:
/* buffer needs to be reinitialized */
LOGFQUEUE("playback < Q_AUDIO_REMAKE_AUDIO_BUFFER");
- audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF);
+ audio_start_playback(NULL, AUDIO_START_RESTART | AUDIO_START_NEWBUF | (ev->data ? AUDIO_START_REFRESH : 0));
if (play_status == PLAY_STOPPED)
return; /* just need to change buffer state */
break;
@@ -3795,15 +3818,57 @@ void audio_set_crossfade(int enable)
#endif /* HAVE_CROSSFADE */
#ifdef HAVE_PLAY_FREQ
+static unsigned long audio_guess_frequency(struct mp3entry *id3)
+{
+ return (id3->frequency % 4000) ? SAMPR_44 : SAMPR_48;
+}
+
+static void audio_change_frequency_callback(unsigned short id, void *data)
+{
+ static bool starting_playback = false;
+ struct mp3entry *id3;
+
+ switch (id)
+ {
+ case PLAYBACK_EVENT_START_PLAYBACK:
+ starting_playback = true;
+ break;
+
+ case PLAYBACK_EVENT_TRACK_CHANGE:
+ id3 = ((struct track_event *)data)->id3;
+ if (id3 && !global_settings.play_frequency)
+ {
+ unsigned long guessed_frequency = audio_guess_frequency(id3);
+ if (mixer_get_frequency() != guessed_frequency)
+ {
+#ifdef PLAYBACK_VOICE
+ voice_stop();
+#endif
+ mixer_set_frequency(guessed_frequency);
+ audio_queue_post(Q_AUDIO_REMAKE_AUDIO_BUFFER, starting_playback);
+ }
+ }
+ starting_playback = false;
+ break;
+
+ default:
+ break;
+ }
+}
+
void audio_set_playback_frequency(int setting)
{
static const unsigned long play_sampr[] = { SAMPR_44, SAMPR_48 };
- if ((unsigned)setting >= ARRAYLEN(play_sampr))
+ if ((unsigned)setting > ARRAYLEN(play_sampr)) /* [0] is "automatic" */
setting = 0;
unsigned long playback_sampr = mixer_get_frequency();
- unsigned long sampr = play_sampr[setting];
+ unsigned long sampr = setting ?
+ play_sampr[setting - 1] :
+ ((audio_status() == AUDIO_STATUS_PLAY) ?
+ audio_guess_frequency(audio_current_track()) :
+ playback_sampr);
if (sampr != playback_sampr)
{
@@ -3829,6 +3894,10 @@ void INIT_ATTR playback_init(void)
track_list_init();
buffering_init();
pcmbuf_update_frequency();
+#ifdef HAVE_PLAY_FREQ
+ add_event(PLAYBACK_EVENT_TRACK_CHANGE, audio_change_frequency_callback);
+ add_event(PLAYBACK_EVENT_START_PLAYBACK, audio_change_frequency_callback);
+#endif
#ifdef HAVE_CROSSFADE
/* Set crossfade setting for next buffer init which should be about... */
pcmbuf_request_crossfade_enable(global_settings.crossfade);
diff --git a/apps/settings_list.c b/apps/settings_list.c
index d322074962..1c33f3dc86 100644
--- a/apps/settings_list.c
+++ b/apps/settings_list.c
@@ -867,8 +867,8 @@ const struct settings_list settings[] = {
), /* CHOICE_SETTING( repeat_mode ) */
#ifdef HAVE_PLAY_FREQ
STRINGCHOICE_SETTING(0, play_frequency, LANG_FREQUENCY, 0,
- "playback frequency", "44.1 kHz,48 kHz", NULL, 2,
- TALK_ID_DECIMAL(441, 1, UNIT_KHZ), TALK_ID(48, UNIT_KHZ)),
+ "playback frequency", "auto,44.1 kHz,48 kHz", NULL, 3,
+ LANG_AUTOMATIC, TALK_ID_DECIMAL(441, 1, UNIT_KHZ), TALK_ID(48, UNIT_KHZ)),
#endif /* HAVE_PLAY_FREQ */
/* LCD */
#ifdef HAVE_LCD_CONTRAST