diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2020-09-30 22:12:35 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2020-10-01 11:56:57 -0400 |
commit | e43726df2cd1cb8275234d60b818d417cfe730b5 (patch) | |
tree | 6f1fb0659dccaafd47394c7de860d4dc3e46b0a4 | |
parent | 6459fa0765745e951a6731974164bbcdc9551dfe (diff) | |
download | rockbox-e43726df2cd1cb8275234d60b818d417cfe730b5.tar.gz rockbox-e43726df2cd1cb8275234d60b818d417cfe730b5.zip |
hosted pcm-alsa improvements
* xduoo x3ii/x20: Better line out support
* less granular volume settings (too many steps before)
* Better handling of swiching sample rates
* Log actual sample rate in debug menu
Most credit goes to Roman Stolyarov
Additional integration [re]work by myself
Change-Id: I63af3740678cf2ed3170f61534e1029c81826bb6
-rw-r--r-- | apps/debug_menu.c | 2 | ||||
-rw-r--r-- | apps/playback.c | 5 | ||||
-rw-r--r-- | firmware/drivers/audio/rocker_codec.c | 30 | ||||
-rw-r--r-- | firmware/drivers/audio/xduoolinux_codec.c | 78 | ||||
-rw-r--r-- | firmware/export/audiohw.h | 6 | ||||
-rw-r--r-- | firmware/export/config/agptekrocker.h | 9 | ||||
-rw-r--r-- | firmware/export/config/xduoox20.h | 8 | ||||
-rw-r--r-- | firmware/export/config/xduoox3ii.h | 5 | ||||
-rw-r--r-- | firmware/export/rocker_codec.h | 4 | ||||
-rw-r--r-- | firmware/export/system.h | 2 | ||||
-rw-r--r-- | firmware/export/xduoolinux_codec.h | 3 | ||||
-rw-r--r-- | firmware/target/hosted/agptek/debug-agptek.c | 52 | ||||
-rw-r--r-- | firmware/target/hosted/pcm-alsa.c | 92 | ||||
-rw-r--r-- | firmware/target/hosted/pcm-alsa.h | 6 | ||||
-rw-r--r-- | firmware/target/hosted/xduoo/debug-xduoo.c | 7 |
15 files changed, 218 insertions, 91 deletions
diff --git a/apps/debug_menu.c b/apps/debug_menu.c index 3df7e97bce..0d2e125185 100644 --- a/apps/debug_menu.c +++ b/apps/debug_menu.c | |||
@@ -2525,7 +2525,7 @@ static const struct { | |||
2525 | { "Screendump", dbg_screendump }, | 2525 | { "Screendump", dbg_screendump }, |
2526 | #endif | 2526 | #endif |
2527 | { "Skin Engine RAM usage", dbg_skin_engine }, | 2527 | { "Skin Engine RAM usage", dbg_skin_engine }, |
2528 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) || (defined(SONY_NWZ_LINUX) && !defined(SIMULATOR)) | 2528 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX) || defined(AGPTEK_ROCKER) || defined(XDUOO_X3II) || defined(XDUOO_X20) && !defined(SIMULATOR) |
2529 | { "View HW info", dbg_hw_info }, | 2529 | { "View HW info", dbg_hw_info }, |
2530 | #endif | 2530 | #endif |
2531 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) | 2531 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) |
diff --git a/apps/playback.c b/apps/playback.c index 922837af18..c7cfef018a 100644 --- a/apps/playback.c +++ b/apps/playback.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include "storage.h" | 44 | #include "storage.h" |
45 | #include "misc.h" | 45 | #include "misc.h" |
46 | #include "settings.h" | 46 | #include "settings.h" |
47 | #include "audiohw.h" | ||
47 | 48 | ||
48 | #ifdef HAVE_TAGCACHE | 49 | #ifdef HAVE_TAGCACHE |
49 | #include "tagcache.h" | 50 | #include "tagcache.h" |
@@ -3850,6 +3851,10 @@ static void audio_change_frequency_callback(unsigned short id, void *data) | |||
3850 | static bool starting_playback = false; | 3851 | static bool starting_playback = false; |
3851 | struct mp3entry *id3; | 3852 | struct mp3entry *id3; |
3852 | 3853 | ||
3854 | #ifdef AUDIOHW_HAVE_SET_OUTPUT | ||
3855 | audiohw_set_output(); | ||
3856 | #endif | ||
3857 | |||
3853 | switch (id) | 3858 | switch (id) |
3854 | { | 3859 | { |
3855 | case PLAYBACK_EVENT_START_PLAYBACK: | 3860 | case PLAYBACK_EVENT_START_PLAYBACK: |
diff --git a/firmware/drivers/audio/rocker_codec.c b/firmware/drivers/audio/rocker_codec.c index 23541a4ddb..5404ff9561 100644 --- a/firmware/drivers/audio/rocker_codec.c +++ b/firmware/drivers/audio/rocker_codec.c | |||
@@ -29,6 +29,9 @@ | |||
29 | 29 | ||
30 | static int fd_hw; | 30 | static int fd_hw; |
31 | 31 | ||
32 | static long int vol_l_hw = 255; | ||
33 | static long int vol_r_hw = 255; | ||
34 | |||
32 | static void hw_open(void) | 35 | static void hw_open(void) |
33 | { | 36 | { |
34 | fd_hw = open("/dev/snd/controlC0", O_RDWR); | 37 | fd_hw = open("/dev/snd/controlC0", O_RDWR); |
@@ -41,19 +44,32 @@ static void hw_close(void) | |||
41 | close(fd_hw); | 44 | close(fd_hw); |
42 | } | 45 | } |
43 | 46 | ||
44 | void audiohw_preinit(void) | 47 | void audiohw_mute(int mute) |
45 | { | 48 | { |
46 | long int hp = 2; | 49 | if(mute) |
50 | { | ||
51 | long int ps0 = 0; | ||
52 | alsa_controls_set_ints("Output Port Switch", 1, &ps0); | ||
53 | } | ||
54 | else | ||
55 | { | ||
56 | long int ps2 = 2; | ||
57 | alsa_controls_set_ints("Output Port Switch", 1, &ps2); | ||
58 | } | ||
59 | } | ||
47 | 60 | ||
61 | void audiohw_preinit(void) | ||
62 | { | ||
48 | alsa_controls_init(); | 63 | alsa_controls_init(); |
49 | hw_open(); | 64 | hw_open(); |
50 | |||
51 | /* Output port switch set to Headphones */ | ||
52 | alsa_controls_set_ints("Output Port Switch", 1, &hp); | ||
53 | } | 65 | } |
54 | 66 | ||
55 | void audiohw_postinit(void) | 67 | void audiohw_postinit(void) |
56 | { | 68 | { |
69 | long int hp = 2; | ||
70 | |||
71 | /* Output port switch set to Headphones */ | ||
72 | alsa_controls_set_ints("Output Port Switch", 1, &hp); | ||
57 | } | 73 | } |
58 | 74 | ||
59 | void audiohw_close(void) | 75 | void audiohw_close(void) |
@@ -69,8 +85,8 @@ void audiohw_set_frequency(int fsel) | |||
69 | 85 | ||
70 | void audiohw_set_volume(int vol_l, int vol_r) | 86 | void audiohw_set_volume(int vol_l, int vol_r) |
71 | { | 87 | { |
72 | long int vol_l_hw = -vol_l/5; | 88 | vol_l_hw = -vol_l/5; |
73 | long int vol_r_hw = -vol_r/5; | 89 | vol_r_hw = -vol_r/5; |
74 | 90 | ||
75 | alsa_controls_set_ints("Left Playback Volume", 1, &vol_l_hw); | 91 | alsa_controls_set_ints("Left Playback Volume", 1, &vol_l_hw); |
76 | alsa_controls_set_ints("Right Playback Volume", 1, &vol_r_hw); | 92 | alsa_controls_set_ints("Right Playback Volume", 1, &vol_r_hw); |
diff --git a/firmware/drivers/audio/xduoolinux_codec.c b/firmware/drivers/audio/xduoolinux_codec.c index 5db4902e5f..eedde1d667 100644 --- a/firmware/drivers/audio/xduoolinux_codec.c +++ b/firmware/drivers/audio/xduoolinux_codec.c | |||
@@ -29,9 +29,14 @@ | |||
29 | #include "panic.h" | 29 | #include "panic.h" |
30 | #include "sysfs.h" | 30 | #include "sysfs.h" |
31 | #include "alsa-controls.h" | 31 | #include "alsa-controls.h" |
32 | #include "pcm-alsa.h" | ||
32 | 33 | ||
33 | static int fd_hw; | 34 | static int fd_hw; |
34 | 35 | ||
36 | static long int vol_l_hw = 255; | ||
37 | static long int vol_r_hw = 255; | ||
38 | static long int last_ps = 0; | ||
39 | |||
35 | static void hw_open(void) | 40 | static void hw_open(void) |
36 | { | 41 | { |
37 | fd_hw = open("/dev/snd/controlC0", O_RDWR); | 42 | fd_hw = open("/dev/snd/controlC0", O_RDWR); |
@@ -44,44 +49,69 @@ static void hw_close(void) | |||
44 | close(fd_hw); | 49 | close(fd_hw); |
45 | } | 50 | } |
46 | 51 | ||
47 | void audiohw_preinit(void) | 52 | void audiohw_mute(int mute) |
48 | { | 53 | { |
49 | alsa_controls_init(); | 54 | if(mute) |
50 | hw_open(); | 55 | { |
56 | #if defined(XDUOO_X3II) | ||
57 | alsa_controls_set_bool("AK4490 Soft Mute", true); | ||
58 | #endif | ||
59 | #if defined(XDUOO_X20) | ||
60 | long int ps0 = (last_ps > 1) ? 1 : 2; | ||
61 | alsa_controls_set_ints("Output Port Switch", 1, &ps0); | ||
62 | #endif | ||
63 | } | ||
64 | else | ||
65 | { | ||
66 | #if defined(XDUOO_X3II) | ||
67 | alsa_controls_set_bool("AK4490 Soft Mute", false); | ||
68 | #endif | ||
69 | #if defined(XDUOO_X20) | ||
70 | alsa_controls_set_ints("Output Port Switch", 1, &last_ps); | ||
71 | #endif | ||
72 | } | ||
51 | } | 73 | } |
52 | 74 | ||
53 | void audiohw_postinit(void) | 75 | void audiohw_set_output(void) |
54 | { | 76 | { |
55 | long int ps = 2; // headset | 77 | long int ps = 2; // headset |
78 | |||
56 | int status = 0; | 79 | int status = 0; |
57 | 80 | ||
58 | const char * const sysfs_lo_switch = "/sys/class/switch/lineout/state"; | 81 | const char * const sysfs_lo_switch = "/sys/class/switch/lineout/state"; |
59 | const char * const sysfs_hs_switch = "/sys/class/switch/headset/state"; | 82 | const char * const sysfs_hs_switch = "/sys/class/switch/headset/state"; |
60 | #ifdef XDUOO_X20 | 83 | #if defined(XDUOO_X20) |
61 | const char * const sysfs_bal_switch = "/sys/class/switch/balance/state"; | 84 | const char * const sysfs_bal_switch = "/sys/class/switch/balance/state"; |
62 | #endif | 85 | #endif |
63 | 86 | ||
64 | #if defined(XDUOO_X3II) | ||
65 | alsa_controls_set_bool("AK4490 Soft Mute", true); | ||
66 | #endif | ||
67 | |||
68 | sysfs_get_int(sysfs_lo_switch, &status); | 87 | sysfs_get_int(sysfs_lo_switch, &status); |
69 | if (status) ps = 1; // lineout | 88 | if (status) ps = 1; // lineout |
70 | 89 | ||
71 | sysfs_get_int(sysfs_hs_switch, &status); | 90 | sysfs_get_int(sysfs_hs_switch, &status); |
72 | if (status) ps = 2; // headset | 91 | if (status) ps = 2; // headset |
73 | 92 | ||
74 | #ifdef XDUOO_X20 | 93 | #if defined(XDUOO_X20) |
75 | sysfs_get_int(sysfs_bal_switch, &status); | 94 | sysfs_get_int(sysfs_bal_switch, &status); |
76 | if (status) ps = 3; // balance | 95 | if (status) ps = 3; // balance |
77 | #endif | 96 | #endif |
78 | 97 | ||
79 | /* Output port switch */ | 98 | if (last_ps != ps) |
80 | alsa_controls_set_ints("Output Port Switch", 1, &ps); | 99 | { |
100 | /* Output port switch */ | ||
101 | last_ps = ps; | ||
102 | alsa_controls_set_ints("Output Port Switch", 1, &last_ps); | ||
103 | } | ||
104 | } | ||
81 | 105 | ||
82 | #if defined(XDUOO_X3II) | 106 | void audiohw_preinit(void) |
83 | alsa_controls_set_bool("AK4490 Soft Mute", false); | 107 | { |
84 | #endif | 108 | alsa_controls_init(); |
109 | hw_open(); | ||
110 | } | ||
111 | |||
112 | void audiohw_postinit(void) | ||
113 | { | ||
114 | audiohw_set_output(); | ||
85 | } | 115 | } |
86 | 116 | ||
87 | void audiohw_close(void) | 117 | void audiohw_close(void) |
@@ -97,24 +127,24 @@ void audiohw_set_frequency(int fsel) | |||
97 | 127 | ||
98 | void audiohw_set_volume(int vol_l, int vol_r) | 128 | void audiohw_set_volume(int vol_l, int vol_r) |
99 | { | 129 | { |
100 | long int vol_l_hw = -vol_l/5; | 130 | vol_l_hw = -vol_l/5; |
101 | long int vol_r_hw = -vol_r/5; | 131 | vol_r_hw = -vol_r/5; |
102 | 132 | ||
103 | alsa_controls_set_ints("Left Playback Volume", 1, &vol_l_hw); | 133 | alsa_controls_set_ints("Left Playback Volume", 1, &vol_l_hw); |
104 | alsa_controls_set_ints("Right Playback Volume", 1, &vol_r_hw); | 134 | alsa_controls_set_ints("Right Playback Volume", 1, &vol_r_hw); |
105 | } | 135 | } |
106 | 136 | ||
107 | void audiohw_set_filter_roll_off(int value) | 137 | void audiohw_set_filter_roll_off(int value) |
108 | { | 138 | { |
109 | /* 0 = fast (sharp); | 139 | /* 0 = Sharp; |
110 | 1 = slow; | 140 | 1 = Slow; |
111 | 2 = fast2 | 141 | 2 = Short Sharp |
112 | 3 = slow2 | 142 | 3 = Short Slow */ |
113 | 4 = NOS ? */ | ||
114 | long int value_hw = value; | ||
115 | #if defined(XDUOO_X3II) | 143 | #if defined(XDUOO_X3II) |
144 | long int value_hw = value; | ||
116 | alsa_controls_set_ints("AK4490 Digital Filter", 1, &value_hw); | 145 | alsa_controls_set_ints("AK4490 Digital Filter", 1, &value_hw); |
117 | #elif defined(XDUOO_X20) | 146 | #elif defined(XDUOO_X20) |
147 | long int value_hw = value; | ||
118 | alsa_controls_set_ints("ES9018_K2M Digital Filter", 1, &value_hw); | 148 | alsa_controls_set_ints("ES9018_K2M Digital Filter", 1, &value_hw); |
119 | #else | 149 | #else |
120 | (void)value; | 150 | (void)value; |
diff --git a/firmware/export/audiohw.h b/firmware/export/audiohw.h index 490c8fc571..34a253e893 100644 --- a/firmware/export/audiohw.h +++ b/firmware/export/audiohw.h | |||
@@ -223,7 +223,7 @@ struct sound_settings_info | |||
223 | #elif defined(HAVE_ROCKER_CODEC) | 223 | #elif defined(HAVE_ROCKER_CODEC) |
224 | #include "rocker_codec.h" | 224 | #include "rocker_codec.h" |
225 | #elif defined(HAVE_XDUOO_LINUX_CODEC) | 225 | #elif defined(HAVE_XDUOO_LINUX_CODEC) |
226 | #include "rocker_codec.h" | 226 | #include "xduoolinux_codec.h" |
227 | #endif | 227 | #endif |
228 | 228 | ||
229 | /* convert caps into defines */ | 229 | /* convert caps into defines */ |
@@ -452,6 +452,10 @@ void audiohw_set_volume(int vol_l, int vol_r); | |||
452 | void audiohw_set_lineout_volume(int vol_l, int vol_r); | 452 | void audiohw_set_lineout_volume(int vol_l, int vol_r); |
453 | #endif | 453 | #endif |
454 | 454 | ||
455 | #ifdef AUDIOHW_HAVE_SET_OUTPUT | ||
456 | void audiohw_set_output(void); | ||
457 | #endif | ||
458 | |||
455 | #ifndef AUDIOHW_HAVE_CLIPPING | 459 | #ifndef AUDIOHW_HAVE_CLIPPING |
456 | #if defined(AUDIOHW_HAVE_BASS) || defined(AUDIOHW_HAVE_TREBLE) \ | 460 | #if defined(AUDIOHW_HAVE_BASS) || defined(AUDIOHW_HAVE_TREBLE) \ |
457 | || defined(AUDIOHW_HAVE_EQ) | 461 | || defined(AUDIOHW_HAVE_EQ) |
diff --git a/firmware/export/config/agptekrocker.h b/firmware/export/config/agptekrocker.h index 31ef904109..f14e65f7e9 100644 --- a/firmware/export/config/agptekrocker.h +++ b/firmware/export/config/agptekrocker.h | |||
@@ -75,10 +75,6 @@ | |||
75 | /* The number of bytes reserved for loadable plugins */ | 75 | /* The number of bytes reserved for loadable plugins */ |
76 | #define PLUGIN_BUFFER_SIZE 0x100000 | 76 | #define PLUGIN_BUFFER_SIZE 0x100000 |
77 | 77 | ||
78 | |||
79 | |||
80 | #define HAVE_ROCKER_CODEC | ||
81 | |||
82 | #define HAVE_HEADPHONE_DETECTION | 78 | #define HAVE_HEADPHONE_DETECTION |
83 | 79 | ||
84 | /* KeyPad configuration for plugins */ | 80 | /* KeyPad configuration for plugins */ |
@@ -108,10 +104,7 @@ | |||
108 | #define CPU_FREQ 1008000000 | 104 | #define CPU_FREQ 1008000000 |
109 | 105 | ||
110 | /* No special storage */ | 106 | /* No special storage */ |
111 | #define CONFIG_STORAGE (STORAGE_HOSTFS)//|STORAGE_SD) | 107 | #define CONFIG_STORAGE STORAGE_HOSTFS |
112 | //#define MULTIDRIVE_DIR "/mnt/sd_0" | ||
113 | //#define NUM_DRIVES 1 | ||
114 | //#define HAVE_HOTSWAP | ||
115 | #define HAVE_STORAGE_FLUSH | 108 | #define HAVE_STORAGE_FLUSH |
116 | 109 | ||
117 | /* Battery */ | 110 | /* Battery */ |
diff --git a/firmware/export/config/xduoox20.h b/firmware/export/config/xduoox20.h index a61f2c3aa7..5da5ee00f3 100644 --- a/firmware/export/config/xduoox20.h +++ b/firmware/export/config/xduoox20.h | |||
@@ -63,18 +63,12 @@ | |||
63 | /* define this if you have a real-time clock */ | 63 | /* define this if you have a real-time clock */ |
64 | #define CONFIG_RTC APPLICATION | 64 | #define CONFIG_RTC APPLICATION |
65 | 65 | ||
66 | /* Define if the device can wake from an RTC alarm */ | ||
67 | //#define HAVE_RTC_ALARM | ||
68 | |||
69 | /* The number of bytes reserved for loadable codecs */ | 66 | /* The number of bytes reserved for loadable codecs */ |
70 | #define CODEC_SIZE 0x80000 | 67 | #define CODEC_SIZE 0x80000 |
71 | 68 | ||
72 | /* The number of bytes reserved for loadable plugins */ | 69 | /* The number of bytes reserved for loadable plugins */ |
73 | #define PLUGIN_BUFFER_SIZE 0x100000 | 70 | #define PLUGIN_BUFFER_SIZE 0x100000 |
74 | 71 | ||
75 | |||
76 | |||
77 | |||
78 | #define HAVE_HEADPHONE_DETECTION | 72 | #define HAVE_HEADPHONE_DETECTION |
79 | 73 | ||
80 | /* KeyPad configuration for plugins */ | 74 | /* KeyPad configuration for plugins */ |
@@ -125,6 +119,8 @@ | |||
125 | /* HW codec is flexible */ | 119 | /* HW codec is flexible */ |
126 | #define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 | 120 | #define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 |
127 | 121 | ||
122 | #define AUDIOHW_HAVE_SET_OUTPUT | ||
123 | |||
128 | /* Battery */ | 124 | /* Battery */ |
129 | #define BATTERY_CAPACITY_DEFAULT 2400 /* default battery capacity */ | 125 | #define BATTERY_CAPACITY_DEFAULT 2400 /* default battery capacity */ |
130 | #define BATTERY_CAPACITY_MIN 2400 /* min. capacity selectable */ | 126 | #define BATTERY_CAPACITY_MIN 2400 /* min. capacity selectable */ |
diff --git a/firmware/export/config/xduoox3ii.h b/firmware/export/config/xduoox3ii.h index 13072ea3dc..678577f5f4 100644 --- a/firmware/export/config/xduoox3ii.h +++ b/firmware/export/config/xduoox3ii.h | |||
@@ -60,9 +60,6 @@ | |||
60 | /* define this if you have a real-time clock */ | 60 | /* define this if you have a real-time clock */ |
61 | #define CONFIG_RTC APPLICATION | 61 | #define CONFIG_RTC APPLICATION |
62 | 62 | ||
63 | /* Define if the device can wake from an RTC alarm */ | ||
64 | //#define HAVE_RTC_ALARM | ||
65 | |||
66 | /* The number of bytes reserved for loadable codecs */ | 63 | /* The number of bytes reserved for loadable codecs */ |
67 | #define CODEC_SIZE 0x80000 | 64 | #define CODEC_SIZE 0x80000 |
68 | 65 | ||
@@ -119,6 +116,8 @@ | |||
119 | /* HW codec is flexible */ | 116 | /* HW codec is flexible */ |
120 | #define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 | 117 | #define HW_SAMPR_CAPS SAMPR_CAP_ALL_192 |
121 | 118 | ||
119 | #define AUDIOHW_HAVE_SET_OUTPUT | ||
120 | |||
122 | /* Battery */ | 121 | /* Battery */ |
123 | #define BATTERY_CAPACITY_DEFAULT 2000 /* default battery capacity */ | 122 | #define BATTERY_CAPACITY_DEFAULT 2000 /* default battery capacity */ |
124 | #define BATTERY_CAPACITY_MIN 2000 /* min. capacity selectable */ | 123 | #define BATTERY_CAPACITY_MIN 2000 /* min. capacity selectable */ |
diff --git a/firmware/export/rocker_codec.h b/firmware/export/rocker_codec.h index 366900d717..673b12b494 100644 --- a/firmware/export/rocker_codec.h +++ b/firmware/export/rocker_codec.h | |||
@@ -2,5 +2,7 @@ | |||
2 | #define __ROCKER_CODEC__ | 2 | #define __ROCKER_CODEC__ |
3 | 3 | ||
4 | #define AUDIOHW_CAPS 0 | 4 | #define AUDIOHW_CAPS 0 |
5 | AUDIOHW_SETTING(VOLUME, "dB", 1, 5, -1020, 0, -300, ) | 5 | AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -127, 0, -30) |
6 | #endif | 6 | #endif |
7 | |||
8 | void audiohw_mute(int mute); | ||
diff --git a/firmware/export/system.h b/firmware/export/system.h index ebeef9c004..cfec235bc4 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h | |||
@@ -347,7 +347,7 @@ static inline void cpu_boost_unlock(void) | |||
347 | #ifndef SIMULATOR | 347 | #ifndef SIMULATOR |
348 | bool dbg_ports(void); | 348 | bool dbg_ports(void); |
349 | #endif | 349 | #endif |
350 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX) | 350 | #if (CONFIG_PLATFORM & PLATFORM_NATIVE) || defined(SONY_NWZ_LINUX) || defined(AGPTEK_ROCKER) || defined(XDUOO_X3II) || defined(XDUOO_X20) |
351 | bool dbg_hw_info(void); | 351 | bool dbg_hw_info(void); |
352 | #endif | 352 | #endif |
353 | 353 | ||
diff --git a/firmware/export/xduoolinux_codec.h b/firmware/export/xduoolinux_codec.h index ccd49f09aa..ea0b2988f1 100644 --- a/firmware/export/xduoolinux_codec.h +++ b/firmware/export/xduoolinux_codec.h | |||
@@ -5,3 +5,6 @@ | |||
5 | AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -127, 0, -30) | 5 | AUDIOHW_SETTING(VOLUME, "dB", 0, 1, -127, 0, -30) |
6 | AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 4, 0) | 6 | AUDIOHW_SETTING(FILTER_ROLL_OFF, "", 0, 1, 0, 4, 0) |
7 | #endif | 7 | #endif |
8 | |||
9 | void audiohw_mute(int mute); | ||
10 | void audiohw_set_output(void); | ||
diff --git a/firmware/target/hosted/agptek/debug-agptek.c b/firmware/target/hosted/agptek/debug-agptek.c index 33f3ac4b97..b4fcb4246b 100644 --- a/firmware/target/hosted/agptek/debug-agptek.c +++ b/firmware/target/hosted/agptek/debug-agptek.c | |||
@@ -1,6 +1,52 @@ | |||
1 | #include <stdbool.h> | 1 | /*************************************************************************** |
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * | ||
9 | * Copyright (C) 2020 by Solomon Peachy | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or | ||
12 | * modify it under the terms of the GNU General Public License | ||
13 | * as published by the Free Software Foundation; either version 2 | ||
14 | * of the License, or (at your option) any later version. | ||
15 | * | ||
16 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
17 | * KIND, either express or implied. | ||
18 | * | ||
19 | ****************************************************************************/ | ||
2 | 20 | ||
3 | bool debug_hw_info(void) | 21 | #include "config.h" |
22 | #include "font.h" | ||
23 | #include "lcd.h" | ||
24 | #include "kernel.h" | ||
25 | #include "button.h" | ||
26 | |||
27 | #ifndef BOOTLOADER | ||
28 | |||
29 | #include "pcm-alsa.h" | ||
30 | |||
31 | static int line = 0; | ||
32 | |||
33 | bool dbg_hw_info(void) | ||
4 | { | 34 | { |
5 | return false; | 35 | int btn = 0; |
36 | |||
37 | lcd_setfont(FONT_SYSFIXED); | ||
38 | |||
39 | while(btn ^ BUTTON_POWER) { | ||
40 | lcd_clear_display(); | ||
41 | line = 0; | ||
42 | |||
43 | lcd_putsf(0, line++, "pcm srate: %d", pcm_alsa_get_rate()); | ||
44 | btn = button_read_device(); | ||
45 | |||
46 | lcd_update(); | ||
47 | sleep(HZ/16); | ||
48 | } | ||
49 | return true; | ||
6 | } | 50 | } |
51 | |||
52 | #endif /* !BOOTLOADER */ | ||
diff --git a/firmware/target/hosted/pcm-alsa.c b/firmware/target/hosted/pcm-alsa.c index 1b8e3c4477..f33b42429c 100644 --- a/firmware/target/hosted/pcm-alsa.c +++ b/firmware/target/hosted/pcm-alsa.c | |||
@@ -68,7 +68,7 @@ | |||
68 | * with multple applications running */ | 68 | * with multple applications running */ |
69 | static char device[] = "plughw:0,0"; /* playback device */ | 69 | static char device[] = "plughw:0,0"; /* playback device */ |
70 | static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */ | 70 | static const snd_pcm_access_t access_ = SND_PCM_ACCESS_RW_INTERLEAVED; /* access mode */ |
71 | #ifdef SONY_NWZ_LINUX | 71 | #if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC) |
72 | /* Sony NWZ must use 32-bit per sample */ | 72 | /* Sony NWZ must use 32-bit per sample */ |
73 | static const snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE; /* sample format */ | 73 | static const snd_pcm_format_t format = SND_PCM_FORMAT_S32_LE; /* sample format */ |
74 | typedef long sample_t; | 74 | typedef long sample_t; |
@@ -77,6 +77,9 @@ static const snd_pcm_format_t format = SND_PCM_FORMAT_S16; /* sample format * | |||
77 | typedef short sample_t; | 77 | typedef short sample_t; |
78 | #endif | 78 | #endif |
79 | static const int channels = 2; /* count of channels */ | 79 | static const int channels = 2; /* count of channels */ |
80 | static unsigned int sample_rate = 0; | ||
81 | static unsigned int real_sample_rate = 0; | ||
82 | |||
80 | static snd_pcm_t *handle = NULL; | 83 | static snd_pcm_t *handle = NULL; |
81 | static snd_pcm_sframes_t buffer_size = MIX_FRAME_SAMPLES * 32; /* ~16k */ | 84 | static snd_pcm_sframes_t buffer_size = MIX_FRAME_SAMPLES * 32; /* ~16k */ |
82 | static snd_pcm_sframes_t period_size = MIX_FRAME_SAMPLES * 4; /* ~4k */ | 85 | static snd_pcm_sframes_t period_size = MIX_FRAME_SAMPLES * 4; /* ~4k */ |
@@ -93,14 +96,13 @@ static char signal_stack[SIGSTKSZ]; | |||
93 | static int recursion; | 96 | static int recursion; |
94 | #endif | 97 | #endif |
95 | 98 | ||
96 | static int set_hwparams(snd_pcm_t *handle, unsigned sample_rate) | 99 | static int set_hwparams(snd_pcm_t *handle) |
97 | { | 100 | { |
98 | unsigned int rrate; | ||
99 | int err; | 101 | int err; |
102 | unsigned int srate; | ||
100 | snd_pcm_hw_params_t *params; | 103 | snd_pcm_hw_params_t *params; |
101 | snd_pcm_hw_params_malloc(¶ms); | 104 | snd_pcm_hw_params_malloc(¶ms); |
102 | 105 | ||
103 | |||
104 | /* choose all parameters */ | 106 | /* choose all parameters */ |
105 | err = snd_pcm_hw_params_any(handle, params); | 107 | err = snd_pcm_hw_params_any(handle, params); |
106 | if (err < 0) | 108 | if (err < 0) |
@@ -130,16 +132,17 @@ static int set_hwparams(snd_pcm_t *handle, unsigned sample_rate) | |||
130 | goto error; | 132 | goto error; |
131 | } | 133 | } |
132 | /* set the stream rate */ | 134 | /* set the stream rate */ |
133 | rrate = sample_rate; | 135 | sample_rate = srate = pcm_sampr; |
134 | err = snd_pcm_hw_params_set_rate_near(handle, params, &rrate, 0); | 136 | err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0); |
135 | if (err < 0) | 137 | if (err < 0) |
136 | { | 138 | { |
137 | printf("Rate %iHz not available for playback: %s\n", sample_rate, snd_strerror(err)); | 139 | printf("Rate %iHz not available for playback: %s\n", sample_rate, snd_strerror(err)); |
138 | goto error; | 140 | goto error; |
139 | } | 141 | } |
140 | if (rrate != sample_rate) | 142 | real_sample_rate = srate; |
143 | if (real_sample_rate != sample_rate) | ||
141 | { | 144 | { |
142 | printf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, rrate); | 145 | printf("Rate doesn't match (requested %iHz, get %iHz)\n", sample_rate, real_sample_rate); |
143 | err = -EINVAL; | 146 | err = -EINVAL; |
144 | goto error; | 147 | goto error; |
145 | } | 148 | } |
@@ -159,8 +162,9 @@ static int set_hwparams(snd_pcm_t *handle, unsigned sample_rate) | |||
159 | printf("Unable to set period size %ld for playback: %s\n", period_size, snd_strerror(err)); | 162 | printf("Unable to set period size %ld for playback: %s\n", period_size, snd_strerror(err)); |
160 | goto error; | 163 | goto error; |
161 | } | 164 | } |
162 | if (!frames) | 165 | |
163 | frames = malloc(period_size * channels * sizeof(sample_t)); | 166 | free(frames); |
167 | frames = calloc(1, period_size * channels * sizeof(sample_t)); | ||
164 | 168 | ||
165 | /* write the parameters to device */ | 169 | /* write the parameters to device */ |
166 | err = snd_pcm_hw_params(handle, params); | 170 | err = snd_pcm_hw_params(handle, params); |
@@ -229,26 +233,37 @@ error: | |||
229 | * and add 48dB to the input volume. We cannot go lower -43dB because several | 233 | * and add 48dB to the input volume. We cannot go lower -43dB because several |
230 | * values between -48dB and -43dB would require a fractional multiplier, which is | 234 | * values between -48dB and -43dB would require a fractional multiplier, which is |
231 | * stupid to implement for such very low volume. */ | 235 | * stupid to implement for such very low volume. */ |
232 | static int dig_vol_mult = 2 ^ 16; /* multiplicative factor to apply to each sample */ | 236 | static int dig_vol_mult_l = 2 ^ 16; /* multiplicative factor to apply to each sample */ |
237 | static int dig_vol_mult_r = 2 ^ 16; /* multiplicative factor to apply to each sample */ | ||
233 | 238 | ||
234 | void pcm_alsa_set_digital_volume(int vol_db) | 239 | void pcm_alsa_set_digital_volume(int vol_db_l, int vol_db_r) |
235 | { | 240 | { |
236 | if(vol_db > 0 || vol_db < -43) | 241 | if(vol_db_l > 0 || vol_db_r > 0 || vol_db_l < -43 || vol_db_r < -43) |
237 | panicf("invalid pcm alsa volume"); | 242 | panicf("invalid pcm alsa volume"); |
238 | if(format != SND_PCM_FORMAT_S32_LE) | 243 | if(format != SND_PCM_FORMAT_S32_LE) |
239 | panicf("this function assumes 32-bit sample size"); | 244 | panicf("this function assumes 32-bit sample size"); |
240 | vol_db += 48; /* -42dB .. 0dB => 5dB .. 48dB */ | 245 | vol_db_l += 48; /* -42dB .. 0dB => 5dB .. 48dB */ |
246 | vol_db_r += 48; /* -42dB .. 0dB => 5dB .. 48dB */ | ||
241 | /* NOTE if vol_dB = 5 then vol_shift = 1 but r = 1 so we do vol_shift - 1 >= 0 | 247 | /* NOTE if vol_dB = 5 then vol_shift = 1 but r = 1 so we do vol_shift - 1 >= 0 |
242 | * otherwise vol_dB >= 0 implies vol_shift >= 2 so vol_shift - 2 >= 0 */ | 248 | * otherwise vol_dB >= 0 implies vol_shift >= 2 so vol_shift - 2 >= 0 */ |
243 | int vol_shift = vol_db / 3; | 249 | int vol_shift_l = vol_db_l / 3; |
244 | int r = vol_db % 3; | 250 | int vol_shift_r = vol_db_r / 3; |
245 | if(r == 0) | 251 | int r_l = vol_db_l % 3; |
246 | dig_vol_mult = 1 << vol_shift; | 252 | int r_r = vol_db_r % 3; |
247 | else if(r == 1) | 253 | if(r_l == 0) |
248 | dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 2); | 254 | dig_vol_mult_l = 1 << vol_shift_l; |
255 | else if(r_l == 1) | ||
256 | dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 2); | ||
257 | else | ||
258 | dig_vol_mult_l = 1 << vol_shift_l | 1 << (vol_shift_l - 1); | ||
259 | printf("l: %d dB -> factor = %d\n", vol_db_l - 48, dig_vol_mult_l); | ||
260 | if(r_r == 0) | ||
261 | dig_vol_mult_r = 1 << vol_shift_r; | ||
262 | else if(r_r == 1) | ||
263 | dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 2); | ||
249 | else | 264 | else |
250 | dig_vol_mult = 1 << vol_shift | 1 << (vol_shift - 1); | 265 | dig_vol_mult_r = 1 << vol_shift_r | 1 << (vol_shift_r - 1); |
251 | printf("%d dB -> factor = %d\n", vol_db - 48, dig_vol_mult); | 266 | printf("r: %d dB -> factor = %d\n", vol_db_r - 48, dig_vol_mult_r); |
252 | } | 267 | } |
253 | 268 | ||
254 | /* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */ | 269 | /* copy pcm samples to a spare buffer, suitable for snd_pcm_writei() */ |
@@ -279,8 +294,11 @@ static bool fill_frames(void) | |||
279 | * sample by some value so the sound is not too low */ | 294 | * sample by some value so the sound is not too low */ |
280 | const short *pcm_ptr = pcm_data; | 295 | const short *pcm_ptr = pcm_data; |
281 | sample_t *sample_ptr = &frames[2*(period_size-frames_left)]; | 296 | sample_t *sample_ptr = &frames[2*(period_size-frames_left)]; |
282 | for (int i = 0; i < copy_n*2; i++) | 297 | for (int i = 0; i < copy_n; i++) |
283 | *sample_ptr++ = *pcm_ptr++ * dig_vol_mult; | 298 | { |
299 | *sample_ptr++ = *pcm_ptr++ * dig_vol_mult_l; | ||
300 | *sample_ptr++ = *pcm_ptr++ * dig_vol_mult_r; | ||
301 | } | ||
284 | } | 302 | } |
285 | else | 303 | else |
286 | { | 304 | { |
@@ -378,7 +396,7 @@ static int async_rw(snd_pcm_t *handle) | |||
378 | 396 | ||
379 | /* fill buffer with silence to initiate playback without noisy click */ | 397 | /* fill buffer with silence to initiate playback without noisy click */ |
380 | sample_size = buffer_size; | 398 | sample_size = buffer_size; |
381 | samples = malloc(sample_size * channels * sizeof(sample_t)); | 399 | samples = calloc(1, sample_size * channels * sizeof(sample_t)); |
382 | 400 | ||
383 | snd_pcm_format_set_silence(format, samples, sample_size); | 401 | snd_pcm_format_set_silence(format, samples, sample_size); |
384 | err = snd_pcm_writei(handle, samples, sample_size); | 402 | err = snd_pcm_writei(handle, samples, sample_size); |
@@ -428,7 +446,7 @@ void pcm_play_dma_init(void) | |||
428 | if ((err = snd_pcm_nonblock(handle, 1))) | 446 | if ((err = snd_pcm_nonblock(handle, 1))) |
429 | panicf("Could not set non-block mode: %s\n", snd_strerror(err)); | 447 | panicf("Could not set non-block mode: %s\n", snd_strerror(err)); |
430 | 448 | ||
431 | if ((err = set_hwparams(handle, pcm_sampr)) < 0) | 449 | if ((err = set_hwparams(handle)) < 0) |
432 | { | 450 | { |
433 | panicf("Setting of hwparams failed: %s\n", snd_strerror(err)); | 451 | panicf("Setting of hwparams failed: %s\n", snd_strerror(err)); |
434 | } | 452 | } |
@@ -473,15 +491,28 @@ void pcm_play_unlock(void) | |||
473 | #endif | 491 | #endif |
474 | } | 492 | } |
475 | 493 | ||
494 | #if defined(HAVE_XDUOO_LINUX_CODEC) || defined(HAVE_FIIO_LINUX_CODEC) || defined(HAVE_ROCKER_CODEC) | ||
495 | static void pcm_dma_apply_settings_nolock(void) | ||
496 | { | ||
497 | if (sample_rate != pcm_sampr) | ||
498 | { | ||
499 | audiohw_mute(true); | ||
500 | snd_pcm_drop(handle); | ||
501 | set_hwparams(handle); | ||
502 | audiohw_mute(false); | ||
503 | } | ||
504 | } | ||
505 | #else | ||
476 | static void pcm_dma_apply_settings_nolock(void) | 506 | static void pcm_dma_apply_settings_nolock(void) |
477 | { | 507 | { |
478 | snd_pcm_drop(handle); | 508 | snd_pcm_drop(handle); |
479 | set_hwparams(handle, pcm_sampr); | 509 | set_hwparams(handle); |
480 | #if defined(HAVE_NWZ_LINUX_CODEC) | 510 | #if defined(HAVE_NWZ_LINUX_CODEC) |
481 | /* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */ | 511 | /* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */ |
482 | audiohw_set_frequency(pcm_sampr); | 512 | audiohw_set_frequency(pcm_sampr); |
483 | #endif | 513 | #endif |
484 | } | 514 | } |
515 | #endif | ||
485 | 516 | ||
486 | void pcm_dma_apply_settings(void) | 517 | void pcm_dma_apply_settings(void) |
487 | { | 518 | { |
@@ -571,11 +602,16 @@ void pcm_play_dma_postinit(void) | |||
571 | audiohw_postinit(); | 602 | audiohw_postinit(); |
572 | } | 603 | } |
573 | 604 | ||
574 | |||
575 | void pcm_set_mixer_volume(int volume) | 605 | void pcm_set_mixer_volume(int volume) |
576 | { | 606 | { |
577 | (void)volume; | 607 | (void)volume; |
578 | } | 608 | } |
609 | |||
610 | int pcm_alsa_get_rate(void) | ||
611 | { | ||
612 | return real_sample_rate; | ||
613 | } | ||
614 | |||
579 | #ifdef HAVE_RECORDING | 615 | #ifdef HAVE_RECORDING |
580 | void pcm_rec_lock(void) | 616 | void pcm_rec_lock(void) |
581 | { | 617 | { |
diff --git a/firmware/target/hosted/pcm-alsa.h b/firmware/target/hosted/pcm-alsa.h index a2514494de..b746f0d259 100644 --- a/firmware/target/hosted/pcm-alsa.h +++ b/firmware/target/hosted/pcm-alsa.h | |||
@@ -22,10 +22,12 @@ | |||
22 | 22 | ||
23 | #include <config.h> | 23 | #include <config.h> |
24 | 24 | ||
25 | #ifdef SONY_NWZ_LINUX | 25 | #if defined(SONY_NWZ_LINUX) || defined(HAVE_FIIO_LINUX_CODEC) |
26 | /* Set the PCM volume in dB: each sample with have this volume applied digitally | 26 | /* Set the PCM volume in dB: each sample with have this volume applied digitally |
27 | * before being sent to ALSA. Volume must satisfy -43 <= dB <= 0 */ | 27 | * before being sent to ALSA. Volume must satisfy -43 <= dB <= 0 */ |
28 | void pcm_alsa_set_digital_volume(int vol_db); | 28 | void pcm_alsa_set_digital_volume(int vol_db_l, int vol_db_r); |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | int pcm_alsa_get_rate(void); | ||
32 | |||
31 | #endif /* __PCM_ALSA_RB_H__ */ | 33 | #endif /* __PCM_ALSA_RB_H__ */ |
diff --git a/firmware/target/hosted/xduoo/debug-xduoo.c b/firmware/target/hosted/xduoo/debug-xduoo.c index 33f3ac4b97..9812b8f8b9 100644 --- a/firmware/target/hosted/xduoo/debug-xduoo.c +++ b/firmware/target/hosted/xduoo/debug-xduoo.c | |||
@@ -1,6 +1 @@ | |||
1 | #include <stdbool.h> | #include "../agptek/debug-agptek.c" | |
2 | |||
3 | bool debug_hw_info(void) | ||
4 | { | ||
5 | return false; | ||
6 | } | ||