Compare commits

...

5 commits

Author SHA1 Message Date
mojyack
dfa33c246b pcm: introduce pcm_sink
move target-specific pcm operations into builtin_pcm_sink.
in subsequent commits, another pcm_sink is added, and it becomes
possible to switch between them.

Change-Id: I8f8b9661e01d6e6472f34224ddc3760856778457
2026-03-02 10:09:11 +09:00
Solomon Peachy
9931781185 Translation updates
- Polish (Adam Rak)
 - Slovak (Matej Golian)
 - US English (myself)

Change-Id: I68eb6405709ce8e964b8cd749377a5df4a7d8f5a
2026-03-01 17:48:25 -05:00
Solomon Peachy
b93f3d0589 updatelang: Update validation check for LANG_VOICED_DATE_FORMAT
Missed this in the previous commit

Change-Id: Ia85a8017abfeca369b0e12723468cbe8018def8f
2026-03-01 16:42:32 -05:00
Solomon Peachy
17edcbd42a talk: Improvements in voicing "years"
* Enhance LANG_VOICED_DATE_FORMAT to distinguish between "numeric year"
   and "grouped year"  (2020 -> "two thousand twenty" vs "twenty twenty",
   respectively)
 * Metadata year voicing will now use "numeric year" if specified in
   LANG_VOICED_DATE_FORMAT instead of always using grouped year.
 * Datetime year voicing respects the format instead of always using
   "numeric year"

Change-Id: Icc25da7c36107d3e4e8c70291f87a915e2bcabd3
2026-03-01 16:31:27 -05:00
yegor chernyshov
c86fd2318d added setting to retain file browser directory on reboots WIP
I added the setting keep_directory which automatically updates
the last directory visited and restores it on next boot

--added manual entry

Change-Id: I0ffe6531d591d693806ce0bf56fe22b99e3315e9
2026-03-01 15:05:09 -05:00
45 changed files with 1008 additions and 482 deletions

View file

@ -453,6 +453,13 @@ int ft_load(struct tree_context* c, const char* tempdir)
check_file_thumbnails(c); /* map .talk to ours */ check_file_thumbnails(c); /* map .talk to ours */
tree_unlock_cache(c); tree_unlock_cache(c);
if (global_settings.keep_directory)
{
path_append(global_status.browse_last_folder, c->currdir, PA_SEP_HARD,
sizeof(global_status.browse_last_folder));
}
return 0; return 0;
} }
static void ft_load_font(char *file) static void ft_load_font(char *file)

View file

@ -14666,7 +14666,7 @@
user: core user: core
<source> <source>
*: "Press LEFT to cancel." *: "Press LEFT to cancel."
android,hifietma*,zenvision: "Press BACK to cancel." android,hifietma*: "Press BACK to cancel."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel." cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel."
ihifi760,ihifi960: "Double tap RETURN to cancel." ihifi760,ihifi960: "Double tap RETURN to cancel."
ihifi770,ihifi770c,ihifi800: "Press HOME to cancel." ihifi770,ihifi770c,ihifi800: "Press HOME to cancel."
@ -14681,7 +14681,7 @@
</source> </source>
<dest> <dest>
*: "Press LEFT to cancel." *: "Press LEFT to cancel."
android,hifietma*,zenvision: "Press BACK to cancel." android,hifietma*: "Press BACK to cancel."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel." cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel."
ihifi760,ihifi960: "Double tap RETURN to cancel." ihifi760,ihifi960: "Double tap RETURN to cancel."
ihifi770,ihifi770c,ihifi800: "Press HOME to cancel." ihifi770,ihifi770c,ihifi800: "Press HOME to cancel."
@ -14696,7 +14696,7 @@
</dest> </dest>
<voice> <voice>
*: "Press LEFT to cancel." *: "Press LEFT to cancel."
android,hifietma*,zenvision: "Press BACK to cancel." android,hifietma*: "Press BACK to cancel."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel." cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel."
ihifi760,ihifi960: "Double tap RETURN to cancel." ihifi760,ihifi960: "Double tap RETURN to cancel."
ihifi770,ihifi770c,ihifi800: "Press HOME to cancel." ihifi770,ihifi770c,ihifi800: "Press HOME to cancel."
@ -15191,7 +15191,7 @@
</phrase> </phrase>
<phrase> <phrase>
id: LANG_VOICED_DATE_FORMAT id: LANG_VOICED_DATE_FORMAT
desc: format string for how dates will be read back. Y == 4-digit year, A == month name, m == numeric month, d == numeric day. For example, "AdY" will read "January 21 2021" desc: format string for how dates will be read back. Y == 4-digit year (grouped), y == 4-digit year (numeric), A == month name, m == numeric month, d == numeric day. For example, for 2021-01-05, "AdY" will be voiced as "January 5 twenty twenty-one" and "dmy" will be voiced as "5 1 two thousand twenty one
user: core user: core
<source> <source>
*: "dAY" *: "dAY"
@ -16956,3 +16956,17 @@
*: "Announce Status" *: "Announce Status"
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_KEEP_DIRECTORY
desc: file browser setting
user: core
<source>
*: "Always remember last folder"
</source>
<dest>
*: "Always remember last folder"
</dest>
<voice>
*: "Always remember last folder"
</voice>
</phrase>

View file

@ -15458,7 +15458,7 @@
</phrase> </phrase>
<phrase> <phrase>
id: LANG_VOICED_DATE_FORMAT id: LANG_VOICED_DATE_FORMAT
desc: format string for how dates will be read back. Y == 4-digit year, A == month name, m == numeric month, d == numeric day. For example, "AdY" will read "January 21 2021" desc: format string for how dates will be read back. Y == 4-digit year (grouped), y == 4-digit year (numeric), A == month name, m == numeric month, d == numeric day. For example, for 2021-01-05, "AdY" will be voiced as "January 5 twenty twenty-one" and "dmy" will be voiced as "5 1 two thousand twenty one
user: core user: core
<source> <source>
*: "dAY" *: "dAY"
@ -17029,3 +17029,17 @@
general_purpose_led: "Use LED indicators" general_purpose_led: "Use LED indicators"
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_KEEP_DIRECTORY
desc: file browser setting
user: core
<source>
*: "Always remember last folder"
</source>
<dest>
*: "Always remember last folder"
</dest>
<voice>
*: "Always remember last folder"
</voice>
</phrase>

View file

@ -14367,7 +14367,7 @@
user: core user: core
<source> <source>
*: "Press LEFT to cancel." *: "Press LEFT to cancel."
android,hifietma*,zenvision: "Press BACK to cancel." android,hifietma*: "Press BACK to cancel."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel." cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel."
ihifi760,ihifi960: "Double tap RETURN to cancel." ihifi760,ihifi960: "Double tap RETURN to cancel."
ihifi770,ihifi770c,ihifi800: "Press HOME to cancel." ihifi770,ihifi770c,ihifi800: "Press HOME to cancel."
@ -14382,7 +14382,7 @@
</source> </source>
<dest> <dest>
*: "Wciśnij LEFT, aby anulować." *: "Wciśnij LEFT, aby anulować."
android,hifietma*,zenvision: "Wciśnij BACK, aby anulować." android,hifietma*: "Wciśnij BACK, aby anulować."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Wciśnij POWER, aby anulować." cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Wciśnij POWER, aby anulować."
ihifi760,ihifi960: "Podwójnie stuknij RETURN, aby anulować." ihifi760,ihifi960: "Podwójnie stuknij RETURN, aby anulować."
ihifi770,ihifi770c,ihifi800: "Wciśnij HOME, aby anulować." ihifi770,ihifi770c,ihifi800: "Wciśnij HOME, aby anulować."
@ -14397,7 +14397,7 @@
</dest> </dest>
<voice> <voice>
*: "Wciśnij left, aby anulować." *: "Wciśnij left, aby anulować."
android,hifietma*,zenvision: "Wciśnij bak, aby anulować." android,hifietma*: "Wciśnij bak, aby anulować."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Wciśnij pałer, aby anulować." cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Wciśnij pałer, aby anulować."
ihifi760,ihifi960: "Podwójnie stuknij ritern, aby anulować." ihifi760,ihifi960: "Podwójnie stuknij ritern, aby anulować."
ihifi770,ihifi770c,ihifi800: "Wciśnij hołm, aby anulować." ihifi770,ihifi770c,ihifi800: "Wciśnij hołm, aby anulować."
@ -16966,3 +16966,17 @@
*: "Informuj o stanie" *: "Informuj o stanie"
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_KEEP_DIRECTORY
desc: file browser setting
user: core
<source>
*: "Always remember last folder"
</source>
<dest>
*: "Zawsze pamiętaj ostatni katalog"
</dest>
<voice>
*: "Zawsze pamiętaj ostatni katalog"
</voice>
</phrase>

View file

@ -1490,7 +1490,7 @@
*: "Replaygain Type" *: "Replaygain Type"
</source> </source>
<dest> <dest>
*: "použiť zosilnenie" *: "Použiť zosilnenie"
</dest> </dest>
<voice> <voice>
*: "Použiť zosilnenie" *: "Použiť zosilnenie"
@ -2335,7 +2335,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
backlight_brightness: "jas" backlight_brightness: "Jas"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -3729,7 +3729,7 @@
*: "Jún" *: "Jún"
</dest> </dest>
<voice> <voice>
*: "jún" *: "Jún"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -4237,10 +4237,10 @@
*: ".talk Clip" *: ".talk Clip"
</source> </source>
<dest> <dest>
*: ".talk mp3 klip" *: ".talk klip"
</dest> </dest>
<voice> <voice>
*: "talk mp3 klip" *: "talk klip"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -5399,11 +5399,11 @@
</source> </source>
<dest> <dest>
*: none *: none
recording: "Pri trvaní aspoň" recording: "pri trvaní aspoň"
</dest> </dest>
<voice> <voice>
*: none *: none
recording: "Pri trvaní aspoň" recording: "pri trvaní aspoň"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -6941,7 +6941,7 @@
*: "Pauza" *: "Pauza"
</dest> </dest>
<voice> <voice>
*: "pauza" *: "Pauza"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -10911,7 +10911,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
gigabeats,samsungypr1: "Šírka pásma " gigabeats,samsungypr1: "Šírka pásma"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -10970,10 +10970,10 @@
*: "Force" *: "Force"
</source> </source>
<dest> <dest>
*: "vnútiť" *: "Vnútiť"
</dest> </dest>
<voice> <voice>
*: "vnútiť" *: "Vnútiť"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12149,7 +12149,7 @@
*: "Predchádzajúca stopa" *: "Predchádzajúca stopa"
</dest> </dest>
<voice> <voice>
*: "predchádzajúca stopa" *: "Predchádzajúca stopa"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12174,7 +12174,7 @@
*: "Number of Players" *: "Number of Players"
</source> </source>
<dest> <dest>
*: "počet hráčov" *: "Počet hráčov"
</dest> </dest>
<voice> <voice>
*: "Počet hráčov" *: "Počet hráčov"
@ -12261,10 +12261,10 @@
*: "Next Track" *: "Next Track"
</source> </source>
<dest> <dest>
*: "ďalšia stopa" *: "Nasledujúca stopa"
</dest> </dest>
<voice> <voice>
*: "Ďalšia stopa" *: "Nasledujúca stopa"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12407,10 +12407,10 @@
*: "Cannot restart playback" *: "Cannot restart playback"
</source> </source>
<dest> <dest>
*: "nemožno reštartovať prehrávanie" *: "Nemožno reštartovať prehrávanie"
</dest> </dest>
<voice> <voice>
*: "nemožno reštartovať prehrávanie" *: "Nemožno reštartovať prehrávanie"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12578,10 +12578,10 @@
*: "2 Key Control" *: "2 Key Control"
</source> </source>
<dest> <dest>
*: "ovládanie dvoma tlačidlami" *: "Ovládanie dvoma tlačidlami"
</dest> </dest>
<voice> <voice>
*: "ovládanie dvoma tlačidlami" *: "Ovládanie dvoma tlačidlami"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12741,7 +12741,7 @@
*: "Priamy" *: "Priamy"
</dest> </dest>
<voice> <voice>
*: "priamy" *: "Priamy"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12770,11 +12770,11 @@
lowmem: none lowmem: none
</source> </source>
<dest> <dest>
*: "hodnoty eq" *: "Hodnoty eq"
lowmem: none lowmem: none
</dest> </dest>
<voice> <voice>
*: "hodnoty výšok a hĺbok" *: "Hodnoty výšok a hĺbok"
lowmem: none lowmem: none
</voice> </voice>
</phrase> </phrase>
@ -12817,7 +12817,7 @@
*: "" *: ""
</dest> </dest>
<voice> <voice>
*: "kôň" *: "Kôň"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12929,10 +12929,10 @@
*: "Move Item Down" *: "Move Item Down"
</source> </source>
<dest> <dest>
*: "posuň položku nadol" *: "Posuň položku nadol"
</dest> </dest>
<voice> <voice>
*: "posuň položku nadol" *: "Posuň položku nadol"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -12957,10 +12957,10 @@
*: "Worm Speed" *: "Worm Speed"
</source> </source>
<dest> <dest>
*: "rýchlosť worma" *: "Rýchlosť worma"
</dest> </dest>
<voice> <voice>
*: "rýchlosť worma" *: "Rýchlosť worma"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -13283,7 +13283,7 @@
</dest> </dest>
<voice> <voice>
*: none *: none
es9018: "krátky" es9018: "Krátky"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -13358,11 +13358,11 @@
</source> </source>
<dest> <dest>
*: none *: none
recording: "priečinok nahrávok" recording: "Priečinok nahrávok"
</dest> </dest>
<voice> <voice>
*: none *: none
recording: "priečinok nahrávok" recording: "Priečinok nahrávok"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -13839,10 +13839,10 @@
*: "Out of Control" *: "Out of Control"
</source> </source>
<dest> <dest>
*: "mimo rozsah" *: "Mimo rozsahu"
</dest> </dest>
<voice> <voice>
*: "mimo rozsah" *: "Mimo rozsahu"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -14067,11 +14067,11 @@
lowmem: none lowmem: none
</source> </source>
<dest> <dest>
*: "nastaviť čas obnovenia (min)" *: "Nastaviť čas obnovenia (min)"
lowmem: none lowmem: none
</dest> </dest>
<voice> <voice>
*: "nastaviť čas obnovenia" *: "Nastaviť čas obnovenia"
lowmem: none lowmem: none
</voice> </voice>
</phrase> </phrase>
@ -14086,7 +14086,7 @@
*: "" *: ""
</dest> </dest>
<voice> <voice>
*: "stlačte play pre spustenie testu batérie, alebo stop pre zrušenie" *: "Stlačte play pre spustenie testu batérie, alebo stop pre zrušenie"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -14098,7 +14098,7 @@
lowmem: none lowmem: none
</source> </source>
<dest> <dest>
*: "preskočiť frejmy" *: "Preskočiť frejmy"
lowmem: none lowmem: none
</dest> </dest>
<voice> <voice>
@ -14393,7 +14393,7 @@
user: core user: core
<source> <source>
*: "Press LEFT to cancel." *: "Press LEFT to cancel."
android,hifietma*,zenvision: "Press BACK to cancel." android,hifietma*: "Press BACK to cancel."
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel." cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Press POWER to cancel."
ihifi760,ihifi960: "Double tap RETURN to cancel." ihifi760,ihifi960: "Double tap RETURN to cancel."
ihifi770,ihifi770c,ihifi800: "Press HOME to cancel." ihifi770,ihifi770c,ihifi800: "Press HOME to cancel."
@ -14409,7 +14409,7 @@
<dest> <dest>
*: "Stlačte LEFT pre zrušenie" *: "Stlačte LEFT pre zrušenie"
android: "Stlačte späť pre zrušenie" android: "Stlačte späť pre zrušenie"
hifietma*,zenvision: "Stlačte BACK pre zrušenie" hifietma*: "Stlačte BACK pre zrušenie"
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Stlačte POWER pre zrušenie" cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Stlačte POWER pre zrušenie"
ihifi760,ihifi960: "Poklepte RETURN pre zrušenie" ihifi760,ihifi960: "Poklepte RETURN pre zrušenie"
ihifi770,ihifi770c,ihifi800: "Stlačte HOME pre zrušenie" ihifi770,ihifi770c,ihifi800: "Stlačte HOME pre zrušenie"
@ -14417,7 +14417,7 @@
mpiohd200: "Poklepte REC pre zrušenie" mpiohd200: "Poklepte REC pre zrušenie"
mpiohd300: "Poklepte MENU pre zrušenie" mpiohd300: "Poklepte MENU pre zrušenie"
rx27generic: "Stlačte VOLUME pre zrušenie" rx27generic: "Stlačte VOLUME pre zrušenie"
sonynwza860: "mapa klávesov nekompletná" sonynwza860: "Mapa klávesov nekompletná"
touchscreen: "Stlačte stred vľavo pre zrušenie" touchscreen: "Stlačte stred vľavo pre zrušenie"
vibe500: "Stlačte PREV pre zrušenie" vibe500: "Stlačte PREV pre zrušenie"
xduoox20,xduoox3,xduoox3ii: "Poklepte HOME pre zrušenie" xduoox20,xduoox3,xduoox3ii: "Poklepte HOME pre zrušenie"
@ -14425,7 +14425,7 @@
<voice> <voice>
*: "Stlačte LEFT pre zrušenie" *: "Stlačte LEFT pre zrušenie"
android: "Stlačte späť pre zrušenie" android: "Stlačte späť pre zrušenie"
hifietma*,zenvision: "Stlačte BACK pre zrušenie" hifietma*: "Stlačte BACK pre zrušenie"
cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Stlačte POWER pre zrušenie" cowond2,creativezenxfi2,ibassodx50,ibassodx90,mrobe500,ondavx747: "Stlačte POWER pre zrušenie"
ihifi760,ihifi960: "Poklepte RETURN pre zrušenie" ihifi760,ihifi960: "Poklepte RETURN pre zrušenie"
ihifi770,ihifi770c,ihifi800: "Stlačte HOME pre zrušenie" ihifi770,ihifi770c,ihifi800: "Stlačte HOME pre zrušenie"
@ -14446,7 +14446,7 @@
*: "Date" *: "Date"
</source> </source>
<dest> <dest>
*: "dátum" *: "Dátum"
</dest> </dest>
<voice> <voice>
*: "Dátum" *: "Dátum"
@ -14474,7 +14474,7 @@
*: "Cancel" *: "Cancel"
</source> </source>
<dest> <dest>
*: "zrušiť" *: "Zrušiť"
</dest> </dest>
<voice> <voice>
*: "Zrušiť" *: "Zrušiť"
@ -16802,7 +16802,7 @@
*: "Logovanie" *: "Logovanie"
</dest> </dest>
<voice> <voice>
*: "logovanie" *: "Logovanie"
</voice> </voice>
</phrase> </phrase>
<phrase> <phrase>
@ -16960,3 +16960,17 @@
*: "Oznámiť status" *: "Oznámiť status"
</voice> </voice>
</phrase> </phrase>
<phrase>
id: LANG_KEEP_DIRECTORY
desc: file browser setting
user: core
<source>
*: "Always remember last folder"
</source>
<dest>
*: "Vždy si zapamätať posledný priečinok"
</dest>
<voice>
*: "Vždy si zapamätať posledný priečinok"
</voice>
</phrase>

View file

@ -199,6 +199,7 @@ static int clear_start_directory(void)
splash(HZ, ID2P(LANG_RESET_DONE_CLEAR)); splash(HZ, ID2P(LANG_RESET_DONE_CLEAR));
return false; return false;
} }
MENUITEM_SETTING(keep_directory, &global_settings.keep_directory, NULL);
MENUITEM_FUNCTION(clear_start_directory_item, 0, ID2P(LANG_RESET_START_DIR), MENUITEM_FUNCTION(clear_start_directory_item, 0, ID2P(LANG_RESET_START_DIR),
clear_start_directory, NULL, Icon_file_view_menu); clear_start_directory, NULL, Icon_file_view_menu);
@ -209,6 +210,7 @@ MAKE_MENU(file_menu, ID2P(LANG_FILE), filemenu_callback, Icon_file_view_menu,
&sort_case, &sort_dir, &sort_file, &interpret_numbers, &sort_case, &sort_dir, &sort_file, &interpret_numbers,
&dirfilter, &show_filename_ext, &browse_current, &dirfilter, &show_filename_ext, &browse_current,
&show_path_in_browser, &show_path_in_browser,
&keep_directory,
&clear_start_directory_item &clear_start_directory_item
#ifdef HAVE_HOTKEY #ifdef HAVE_HOTKEY
,&hotkey_tree_item ,&hotkey_tree_item

View file

@ -2039,6 +2039,12 @@ void validate_start_directory_init(void) /* INIT_ATTR */
path_append(dirpath, PATH_ROOTSTR, path_append(dirpath, PATH_ROOTSTR,
PA_SEP_HARD, sizeof(global_settings.start_directory)); PA_SEP_HARD, sizeof(global_settings.start_directory));
} }
if (!global_settings.keep_directory) /* reset to root / if !keep_directory */
{
path_append(global_status.browse_last_folder, PATH_ROOTSTR, PA_SEP_HARD,
sizeof(global_status.browse_last_folder));
}
} }
#endif /* ndef __PCTOOL__ */ #endif /* ndef __PCTOOL__ */

View file

@ -647,6 +647,7 @@ static const struct plugin_api rockbox_api = {
pcm_apply_settings, pcm_apply_settings,
pcm_play_lock, pcm_play_lock,
pcm_play_unlock, pcm_play_unlock,
pcm_current_sink_caps,
beep_play, beep_play,
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
&rec_freq_sampr[0], &rec_freq_sampr[0],

View file

@ -93,6 +93,7 @@ int plugin_open(const char *plugin, const char *parameter);
#include "misc.h" #include "misc.h"
#include "pathfuncs.h" #include "pathfuncs.h"
#include "pcm_mixer.h" #include "pcm_mixer.h"
#include "pcm_sink.h"
#include "dsp-util.h" #include "dsp-util.h"
#include "dsp_core.h" #include "dsp_core.h"
#include "dsp_proc_settings.h" #include "dsp_proc_settings.h"
@ -745,6 +746,7 @@ struct plugin_api {
void (*pcm_apply_settings)(void); void (*pcm_apply_settings)(void);
void (*pcm_play_lock)(void); void (*pcm_play_lock)(void);
void (*pcm_play_unlock)(void); void (*pcm_play_unlock)(void);
const struct pcm_sink_caps* (*pcm_current_sink_caps)(void);
void (*beep_play)(unsigned int frequency, unsigned int duration, void (*beep_play)(unsigned int frequency, unsigned int duration,
unsigned int amplitude); unsigned int amplitude);
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING

View file

@ -118,7 +118,9 @@ static int browser(void* param)
int filter = SHOW_SUPPORTED; int filter = SHOW_SUPPORTED;
char folder[MAX_PATH] = "/"; char folder[MAX_PATH] = "/";
/* stuff needed to remember position in file browser */ /* stuff needed to remember position in file browser */
static char last_folder[MAX_PATH] = "/"; /*static char last_folder[MAX_PATH] = "/"*/
char *last_folder = global_status.browse_last_folder;
/* and stuff for the database browser */ /* and stuff for the database browser */
#ifdef HAVE_TAGCACHE #ifdef HAVE_TAGCACHE
static int last_db_dirlevel = 0, last_db_selection = 0, last_ft_dirlevel = 0; static int last_db_dirlevel = 0, last_db_selection = 0, last_ft_dirlevel = 0;

View file

@ -593,21 +593,28 @@ static const char * id3_get_or_speak_info(int selected_item, void* data,
if(say_it && val) if(say_it && val)
talk_spell(val, true); talk_spell(val, true);
break; break;
case LANG_ID3_YEAR: case LANG_ID3_YEAR: {
const char *format = str(LANG_VOICED_DATE_FORMAT);
bool numericyear = strrchr(format, 'y');
if (id3->year_string) if (id3->year_string)
{ {
val = id3->year_string; val = id3->year_string;
if(say_it && val) if(say_it && val)
say_number_and_spell(val, true); say_number_and_spell(val, !numericyear);
} }
else if (id3->year) else if (id3->year)
{ {
itoa_buf(buffer, buffer_len, id3->year); itoa_buf(buffer, buffer_len, id3->year);
val = buffer; val = buffer;
if(say_it) if(say_it) {
talk_value(id3->year, UNIT_DATEYEAR, true); if (numericyear)
talk_number(id3->year, true);
else
talk_value(id3->year, UNIT_DATEYEAR, true);
}
} }
break; break;
}
case LANG_ID3_LENGTH: case LANG_ID3_LENGTH:
length = info->track_ct > 1 ? id3->length : id3->length / 1000; length = info->track_ct > 1 ? id3->length : id3->length / 1000;

View file

@ -628,6 +628,11 @@ static bool settings_write_config(const char* filename, int options)
case SETTINGS_SAVE_RESUMEINFO: case SETTINGS_SAVE_RESUMEINFO:
if (!(setting->flags & F_RESUMESETTING)) if (!(setting->flags & F_RESUMESETTING))
continue; continue;
if (setting->setting == &global_status.browse_last_folder
&& (!global_settings.keep_directory))
{
continue;
}
break; break;
case SETTINGS_SAVE_ALL: case SETTINGS_SAVE_ALL:
{ {

View file

@ -365,6 +365,7 @@ struct system_status
int font_id[NB_SCREENS]; /* font id of the settings font for each screen */ int font_id[NB_SCREENS]; /* font id of the settings font for each screen */
bool resume_modified; /* playlist is modified (=> warn before erase) */ bool resume_modified; /* playlist is modified (=> warn before erase) */
char browse_last_folder[MAX_PATH];/* only saved if keep_directory = true */
}; };
struct user_settings struct user_settings
@ -893,6 +894,7 @@ struct user_settings
char start_directory[MAX_PATHNAME+1]; char start_directory[MAX_PATHNAME+1];
/* Has the root been customized from the .cfg file? false = no, true = loaded from cfg */ /* Has the root been customized from the .cfg file? false = no, true = loaded from cfg */
bool keep_directory; /* this saves the last path visited in the file browser */
bool root_menu_customized; bool root_menu_customized;
#ifdef HAVE_QUICKSCREEN #ifdef HAVE_QUICKSCREEN
bool shortcuts_replaces_qs; bool shortcuts_replaces_qs;

View file

@ -148,6 +148,13 @@
#define SYSTEM_STATUS(flags,var,default,name) \ #define SYSTEM_STATUS(flags,var,default,name) \
{flags|F_RESUMESETTING|F_T_INT, &global_status.var,-1, \ {flags|F_RESUMESETTING|F_T_INT, &global_status.var,-1, \
INT(default), name, UNUSED} INT(default), name, UNUSED}
#define SYSTEM_STATUS_TEXT_SETTING(flags,var,name,default,prefix,suffix) \
{flags|F_RESUMESETTING|F_T_UCHARPTR, &global_status.var,-1, \
CHARPTR(default),name, \
{.filename_setting= \
(struct filename_setting[]){ \
{prefix,suffix,sizeof(global_status.var)}}} }
/* system_status settings items will be saved to resume.cfg /* system_status settings items will be saved to resume.cfg
Use for int which use the set_sound() function to set them Use for int which use the set_sound() function to set them
These items WILL be included in the users exported settings files These items WILL be included in the users exported settings files
@ -1498,6 +1505,9 @@ const struct settings_list settings[] = {
#endif /* HAVE_DISK_STORAGE */ #endif /* HAVE_DISK_STORAGE */
/* browser */ /* browser */
TEXT_SETTING(0, start_directory, "start directory", "/", NULL, NULL), TEXT_SETTING(0, start_directory, "start directory", "/", NULL, NULL),
SYSTEM_STATUS_TEXT_SETTING(0, browse_last_folder, "last folder", "/", NULL, NULL),
OFFON_SETTING(0, keep_directory, LANG_KEEP_DIRECTORY, false, "keep directory", NULL),
CHOICE_SETTING(0, dirfilter, LANG_FILTER, SHOW_SUPPORTED, "show files", CHOICE_SETTING(0, dirfilter, LANG_FILTER, SHOW_SUPPORTED, "show files",
"all,supported,music,playlists", NULL, 4, ID2P(LANG_ALL), "all,supported,music,playlists", NULL, 4, ID2P(LANG_ALL),
ID2P(LANG_FILTER_SUPPORTED), ID2P(LANG_FILTER_MUSIC), ID2P(LANG_FILTER_SUPPORTED), ID2P(LANG_FILTER_MUSIC),

View file

@ -1566,9 +1566,12 @@ void talk_date(const struct tm *tm, bool enqueue)
for (ptr = format ; *ptr ; ptr++) { for (ptr = format ; *ptr ; ptr++) {
switch(*ptr) { switch(*ptr) {
case 'Y': case 'y':
talk_number(1900 + tm->tm_year, true); talk_number(1900 + tm->tm_year, true);
break; break;
case 'Y':
talk_year(1900 + tm->tm_year, true);
break;
case 'A': case 'A':
talk_id(LANG_MONTH_JANUARY + tm->tm_mon, true); talk_id(LANG_MONTH_JANUARY + tm->tm_mon, true);
break; break;

View file

@ -756,6 +756,7 @@ Nyx Guan
Arin Kim Arin Kim
Ingmar Steen Ingmar Steen
Lourenço Soares Lourenço Soares
Yegor Chernyshov
The libmad team The libmad team
The wavpack team The wavpack team

View file

@ -1783,6 +1783,10 @@ void pcm_play_unlock(void)
\group sound \group sound
\description \description
const struct pcm_sink_caps* pcm_current_sink_caps(enum pcm_sink_ids sink)
\group sound
\description
void pcm_record_data(pcm_rec_callback_type more_ready, pcm_status_callback_type status_cb, void *start, size_t size) void pcm_record_data(pcm_rec_callback_type more_ready, pcm_status_callback_type status_cb, void *start, size_t size)
\group sound \group sound
\conditions (defined(HAVE_RECORDING)) \conditions (defined(HAVE_RECORDING))

View file

@ -22,7 +22,11 @@
#ifndef PCM_INTERNAL_H #ifndef PCM_INTERNAL_H
#define PCM_INTERNAL_H #define PCM_INTERNAL_H
#include <stdbool.h>
#include "config.h" #include "config.h"
#include "pcm.h"
#include "pcm_sink.h"
#include "gcc_extensions.h" /* for FORCE_INLINE */ #include "gcc_extensions.h" /* for FORCE_INLINE */
#ifdef HAVE_SW_VOLUME_CONTROL #ifdef HAVE_SW_VOLUME_CONTROL
@ -129,24 +133,12 @@ void pcm_play_stop_int(void);
bool pcm_play_dma_complete_callback(enum pcm_dma_status status, bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
const void **addr, size_t *size); const void **addr, size_t *size);
extern unsigned long pcm_curr_sampr;
extern unsigned long pcm_sampr;
extern int pcm_fsel;
#ifdef HAVE_PCM_DMA_ADDRESS #ifdef HAVE_PCM_DMA_ADDRESS
void * pcm_dma_addr(void *addr); void * pcm_dma_addr(void *addr);
#endif #endif
extern volatile bool pcm_playing; extern volatile bool pcm_playing;
struct pcm_sink* pcm_get_current_sink(void);
void pcm_play_dma_lock(void);
void pcm_play_dma_unlock(void);
void pcm_play_dma_init(void) INIT_ATTR;
void pcm_play_dma_postinit(void);
void pcm_play_dma_start(const void *addr, size_t size);
void pcm_play_dma_stop(void);
void pcm_dma_apply_settings(void);
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING

View file

@ -71,6 +71,12 @@ void pcm_init(void) INIT_ATTR;
void pcm_postinit(void); void pcm_postinit(void);
bool pcm_is_initialized(void); bool pcm_is_initialized(void);
enum pcm_sink_ids pcm_current_sink(void);
const struct pcm_sink_caps* pcm_sink_caps(enum pcm_sink_ids sink);
/* shortcut for plugins */
const struct pcm_sink_caps* pcm_current_sink_caps(void);
/* This is for playing "raw" PCM data */ /* This is for playing "raw" PCM data */
void pcm_play_data(pcm_play_callback_type get_more, void pcm_play_data(pcm_play_callback_type get_more,
pcm_status_callback_type status_cb, pcm_status_callback_type status_cb,

View file

@ -0,0 +1,57 @@
/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
*
* Copyright (C) 2025 by Sho Tanimoto
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#pragma once
#include <stddef.h>
#include <stdint.h>
struct pcm_sink_caps {
const unsigned long* samprs;
uint16_t num_samprs;
uint16_t default_freq;
};
struct pcm_sink_ops {
void (*init)(void);
void (*postinit)(void);
void (*set_freq)(uint16_t freq);
void (*lock)(void);
void (*unlock)(void);
void (*play)(const void* addr, size_t size);
void (*stop)(void);
};
struct pcm_sink {
/* characteristics */
const struct pcm_sink_caps caps;
/* operations */
const struct pcm_sink_ops ops;
/* runtime states */
unsigned long pending_freq;
unsigned long configured_freq;
};
enum pcm_sink_ids {
PCM_SINK_BUILTIN = 0,
};
/* defined in each platform pcm source */
extern struct pcm_sink builtin_pcm_sink;

View file

@ -42,21 +42,19 @@
* Semi-private - * Semi-private -
* pcm_play_dma_complete_callback * pcm_play_dma_complete_callback
* pcm_play_dma_status_callback * pcm_play_dma_status_callback
* pcm_play_dma_init * pcm_get_current_sink
* pcm_play_dma_postinit * pcm_sink.init
* pcm_play_dma_start * pcm_sink.postinit
* pcm_play_dma_stop * pcm_sink.play
* pcm_sink.stop
* Data Read/Written within TSP - * Data Read/Written within TSP -
* pcm_sampr (R)
* pcm_fsel (R)
* pcm_curr_sampr (R)
* pcm_playing (R) * pcm_playing (R)
* *
* ==Playback/Recording== * ==Playback/Recording==
* Public - * Public -
* pcm_dma_addr * pcm_dma_addr
* Semi-private - * Semi-private -
* pcm_dma_apply_settings * pcm_sink.set_freq
* *
* ==Recording== * ==Recording==
* Public - * Public -
@ -81,6 +79,12 @@
/* 'true' when all stages of pcm initialization have completed */ /* 'true' when all stages of pcm initialization have completed */
static bool pcm_is_ready = false; static bool pcm_is_ready = false;
static struct pcm_sink* sinks[1] = {
[PCM_SINK_BUILTIN] = &builtin_pcm_sink,
};
static enum pcm_sink_ids cur_sink = PCM_SINK_BUILTIN;
static struct mutex sink_mutex; /* protects sinks and cur_sink */
/* The registered callback function to ask for more mp3 data */ /* The registered callback function to ask for more mp3 data */
volatile pcm_play_callback_type volatile pcm_play_callback_type
pcm_callback_for_more SHAREDBSS_ATTR = NULL; pcm_callback_for_more SHAREDBSS_ATTR = NULL;
@ -89,16 +93,14 @@ volatile pcm_status_callback_type
pcm_play_status_callback SHAREDBSS_ATTR = NULL; pcm_play_status_callback SHAREDBSS_ATTR = NULL;
/* PCM playback state */ /* PCM playback state */
volatile bool pcm_playing SHAREDBSS_ATTR = false; volatile bool pcm_playing SHAREDBSS_ATTR = false;
/* samplerate of currently playing audio - undefined if stopped */
unsigned long pcm_curr_sampr SHAREDBSS_ATTR = 0;
/* samplerate waiting to be set */
unsigned long pcm_sampr SHAREDBSS_ATTR = HW_SAMPR_DEFAULT;
/* samplerate frequency selection index */
int pcm_fsel SHAREDBSS_ATTR = HW_FREQ_DEFAULT;
static void pcm_play_data_start_int(const void *addr, size_t size);
void pcm_play_stop_int(void); void pcm_play_stop_int(void);
struct pcm_sink* pcm_get_current_sink(void)
{
return sinks[cur_sink];
}
#if !defined(HAVE_SW_VOLUME_CONTROL) || defined(PCM_SW_VOLUME_UNBUFFERED) #if !defined(HAVE_SW_VOLUME_CONTROL) || defined(PCM_SW_VOLUME_UNBUFFERED)
/** Standard hw volume/unbuffered control functions - otherwise, see /** Standard hw volume/unbuffered control functions - otherwise, see
** pcm_sw_volume.c **/ ** pcm_sw_volume.c **/
@ -108,12 +110,12 @@ static inline void pcm_play_dma_start_int(const void *addr, size_t size)
/* Smoothed transition might not have happened so sync now */ /* Smoothed transition might not have happened so sync now */
pcm_sync_pcm_factors(); pcm_sync_pcm_factors();
#endif #endif
pcm_play_dma_start(addr, size); sinks[cur_sink]->ops.play(addr, size);
} }
static inline void pcm_play_dma_stop_int(void) static inline void pcm_play_dma_stop_int(void)
{ {
pcm_play_dma_stop(); sinks[cur_sink]->ops.stop();
} }
bool pcm_play_dma_complete_callback(enum pcm_dma_status status, bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
@ -123,8 +125,9 @@ bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
if (status < PCM_DMAST_OK) if (status < PCM_DMAST_OK)
status = pcm_play_dma_status_callback(status); status = pcm_play_dma_status_callback(status);
if (status >= PCM_DMAST_OK && pcm_get_more_int(addr, size)) if (status >= PCM_DMAST_OK && pcm_get_more_int(addr, size)) {
return true; return true;
}
/* Error, callback missing or no more DMA to do */ /* Error, callback missing or no more DMA to do */
pcm_play_stop_int(); pcm_play_stop_int();
@ -132,25 +135,6 @@ bool pcm_play_dma_complete_callback(enum pcm_dma_status status,
} }
#endif /* !HAVE_SW_VOLUME_CONTROL || PCM_SW_VOLUME_UNBUFFERED */ #endif /* !HAVE_SW_VOLUME_CONTROL || PCM_SW_VOLUME_UNBUFFERED */
static void pcm_play_data_start_int(const void *addr, size_t size)
{
ALIGN_AUDIOBUF(addr, size);
if ((addr && size) || pcm_get_more_int(&addr, &size))
{
pcm_apply_settings();
logf(" pcm_play_dma_start_int");
pcm_play_dma_start_int(addr, size);
pcm_playing = true;
}
else
{
/* Force a stop */
logf(" pcm_play_stop_int");
pcm_play_stop_int();
}
}
void pcm_play_stop_int(void) void pcm_play_stop_int(void)
{ {
pcm_play_dma_stop_int(); pcm_play_dma_stop_int();
@ -223,7 +207,15 @@ void pcm_do_peak_calculation(struct pcm_peaks *peaks, bool active,
if (active) if (active)
{ {
int framecount = peaks->period*pcm_curr_sampr / HZ; struct pcm_sink* sink = sinks[cur_sink];
if (sink->configured_freq == -1UL)
{
logf("not configured yet");
return;
}
unsigned long sampr = sink->caps.samprs[sink->configured_freq];
int framecount = peaks->period * sampr / HZ;
count = MIN(framecount, count); count = MIN(framecount, count);
if (count > 0) if (count > 0)
@ -247,16 +239,29 @@ bool pcm_is_playing(void)
* interface * interface
*/ */
void pcm_play_lock(void) {
mutex_lock(&sink_mutex);
sinks[cur_sink]->ops.lock();
/* hold sink_mutex until pcm_play_unlock() */
}
void pcm_play_unlock(void) {
sinks[cur_sink]->ops.unlock();
mutex_unlock(&sink_mutex);
}
/* This should only be called at startup before any audio playback or /* This should only be called at startup before any audio playback or
recording is attempted */ recording is attempted */
void pcm_init(void) void pcm_init(void)
{ {
logf("pcm_init"); logf("pcm_init");
pcm_set_frequency(HW_SAMPR_DEFAULT); mutex_init(&sink_mutex);
for(size_t i = 0; i < ARRAYLEN(sinks); i += 1) {
logf(" pcm_play_dma_init"); sinks[i]->pending_freq = sinks[i]->caps.default_freq;
pcm_play_dma_init(); sinks[i]->configured_freq = -1UL;
sinks[i]->ops.init();
}
} }
/* Finish delayed init */ /* Finish delayed init */
@ -264,9 +269,9 @@ void pcm_postinit(void)
{ {
logf("pcm_postinit"); logf("pcm_postinit");
logf(" pcm_play_dma_postinit"); for(size_t i = 0; i < ARRAYLEN(sinks); i += 1) {
sinks[i]->ops.postinit();
pcm_play_dma_postinit(); }
pcm_is_ready = true; pcm_is_ready = true;
} }
@ -276,6 +281,21 @@ bool pcm_is_initialized(void)
return pcm_is_ready; return pcm_is_ready;
} }
enum pcm_sink_ids pcm_current_sink(void)
{
return cur_sink;
}
const struct pcm_sink_caps* pcm_sink_caps(enum pcm_sink_ids sink)
{
return &sinks[sink]->caps;
}
const struct pcm_sink_caps* pcm_current_sink_caps(void)
{
return pcm_sink_caps(pcm_current_sink());
}
void pcm_play_data(pcm_play_callback_type get_more, void pcm_play_data(pcm_play_callback_type get_more,
pcm_status_callback_type status_cb, pcm_status_callback_type status_cb,
const void *start, size_t size) const void *start, size_t size)
@ -287,8 +307,20 @@ void pcm_play_data(pcm_play_callback_type get_more,
pcm_callback_for_more = get_more; pcm_callback_for_more = get_more;
pcm_play_status_callback = status_cb; pcm_play_status_callback = status_cb;
logf(" pcm_play_data_start_int"); ALIGN_AUDIOBUF(start, size);
pcm_play_data_start_int(start, size); if ((start && size) || pcm_get_more_int(&start, &size))
{
pcm_apply_settings();
logf(" pcm_play_dma_start_int");
pcm_play_dma_start_int(start, size);
pcm_playing = true;
}
else
{
/* Force a stop */
logf(" pcm_play_stop_int");
pcm_play_stop_int();
}
pcm_play_unlock(); pcm_play_unlock();
} }
@ -329,20 +361,22 @@ void pcm_set_frequency(unsigned int samplerate)
samplerate = pcm_sampr_to_hw_sampr(samplerate, type); samplerate = pcm_sampr_to_hw_sampr(samplerate, type);
#endif /* CONFIG_SAMPR_TYPES */ #endif /* CONFIG_SAMPR_TYPES */
index = round_value_to_list32(samplerate, hw_freq_sampr, mutex_lock(&sink_mutex);
HW_NUM_FREQ, false); struct pcm_sink* sink = sinks[cur_sink];
index = round_value_to_list32(samplerate, sink->caps.samprs, sink->caps.num_samprs, false);
if (samplerate != hw_freq_sampr[index]) if (samplerate != sink->caps.samprs[index])
index = HW_FREQ_DEFAULT; /* Invalid = default */ index = sink->caps.default_freq; /* Invalid = default */
pcm_sampr = hw_freq_sampr[index]; sink->pending_freq = index;
pcm_fsel = index; mutex_unlock(&sink_mutex);
} }
/* return last-set frequency */ /* return last-set frequency */
unsigned int pcm_get_frequency(void) unsigned int pcm_get_frequency(void)
{ {
return pcm_sampr; struct pcm_sink* sink = sinks[cur_sink];
return sink->caps.samprs[sink->pending_freq];
} }
/* apply pcm settings to the hardware */ /* apply pcm settings to the hardware */
@ -352,12 +386,14 @@ void pcm_apply_settings(void)
pcm_wait_for_init(); pcm_wait_for_init();
if (pcm_sampr != pcm_curr_sampr) mutex_lock(&sink_mutex);
{ struct pcm_sink* sink = sinks[cur_sink];
logf(" pcm_dma_apply_settings"); if(sink->pending_freq != sink->configured_freq) {
pcm_dma_apply_settings(); logf(" sink->set_freq");
pcm_curr_sampr = pcm_sampr; sink->ops.set_freq(sink->pending_freq);
sink->configured_freq = sink->pending_freq;
} }
mutex_unlock(&sink_mutex);
} }
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING

View file

@ -325,7 +325,7 @@ static void start_pcm(bool reframe)
pcm_play_dma_status_callback(PCM_DMAST_STARTED); pcm_play_dma_status_callback(PCM_DMAST_STARTED);
pcm_play_dma_status_callback(PCM_DMAST_STARTED); pcm_play_dma_status_callback(PCM_DMAST_STARTED);
pcm_play_dma_start(pcm_dbl_buf[1], pcm_dbl_buf_size[1]); pcm_get_current_sink()->ops.play(pcm_dbl_buf[1], pcm_dbl_buf_size[1]);
} }
void pcm_play_dma_start_int(const void *addr, size_t size) void pcm_play_dma_start_int(const void *addr, size_t size)
@ -338,7 +338,7 @@ void pcm_play_dma_start_int(const void *addr, size_t size)
void pcm_play_dma_stop_int(void) void pcm_play_dma_stop_int(void)
{ {
pcm_play_dma_stop(); pcm_get_current_sink()->ops.stop();
src_buf_addr = NULL; src_buf_addr = NULL;
src_buf_rem = 0; src_buf_rem = 0;
} }

View file

@ -31,6 +31,7 @@
#include "mmu-arm.h" #include "mmu-arm.h"
#include "cpucache-arm.h" #include "cpucache-arm.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
#define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA #define MAX_TRANSFER (4*((1<<11)-1)) /* maximum data we can transfer via DMA
* i.e. 32 bits at once (size of I2SO_DATA) * i.e. 32 bits at once (size of I2SO_DATA)
@ -53,13 +54,13 @@ static bool volatile is_recording = false;
#endif #endif
/* Mask the DMA interrupt */ /* Mask the DMA interrupt */
void pcm_play_lock(void) static void sink_lock(void)
{ {
++locked; ++locked;
} }
/* Unmask the DMA interrupt if enabled */ /* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if(--locked == 0 && is_playing) if(--locked == 0 && is_playing)
{ {
@ -119,7 +120,7 @@ static void dma_callback(void)
} }
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
is_playing = true; is_playing = true;
@ -136,7 +137,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
play_start_pcm(); play_start_pcm();
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
is_playing = false; is_playing = false;
@ -153,20 +154,6 @@ void pcm_play_dma_stop(void)
play_callback_pending = false; play_callback_pending = false;
} }
void pcm_play_dma_init(void)
{
bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE);
I2SOUT_CONTROL = (1<<6) | (1<<3); /* enable dma, stereo */
audiohw_preinit();
pcm_dma_apply_settings();
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
/* divider is 9 bits but the highest one (for 8kHz) fit in 8 bits */ /* divider is 9 bits but the highest one (for 8kHz) fit in 8 bits */
static const unsigned char divider[SAMPR_NUM_FREQ] = { static const unsigned char divider[SAMPR_NUM_FREQ] = {
[HW_FREQ_96] = ((AS3525_MCLK_FREQ/128 + SAMPR_96/2) / SAMPR_96) - 1, [HW_FREQ_96] = ((AS3525_MCLK_FREQ/128 + SAMPR_96/2) / SAMPR_96) - 1,
@ -183,12 +170,7 @@ static const unsigned char divider[SAMPR_NUM_FREQ] = {
[HW_FREQ_8 ] = ((AS3525_MCLK_FREQ/128 + SAMPR_8 /2) / SAMPR_8 ) - 1, [HW_FREQ_8 ] = ((AS3525_MCLK_FREQ/128 + SAMPR_8 /2) / SAMPR_8 ) - 1,
}; };
static inline unsigned char mclk_divider(void) static void sink_set_freq(uint16_t freq)
{
return divider[pcm_fsel];
}
void pcm_dma_apply_settings(void)
{ {
bitmod32(&CGU_AUDIO, bitmod32(&CGU_AUDIO,
(0<<24) | /* I2SI_MCLK2PAD_EN = disabled */ (0<<24) | /* I2SI_MCLK2PAD_EN = disabled */
@ -196,11 +178,20 @@ void pcm_dma_apply_settings(void)
(0<<14) | /* I2SI_MCLK_DIV_SEL = unused */ (0<<14) | /* I2SI_MCLK_DIV_SEL = unused */
(0<<12) | /* I2SI_MCLK_SEL = clk_main */ (0<<12) | /* I2SI_MCLK_SEL = clk_main */
(1<<11) | /* I2SO_MCLK_EN */ (1<<11) | /* I2SO_MCLK_EN */
(mclk_divider() << 2) | /* I2SO_MCLK_DIV_SEL */ (divider[freq] << 2) | /* I2SO_MCLK_DIV_SEL */
(AS3525_MCLK_SEL << 0), /* I2SO_MCLK_SEL */ (AS3525_MCLK_SEL << 0), /* I2SO_MCLK_SEL */
0x01ffffff); 0x01ffffff);
} }
static void sink_dma_init(void)
{
bitset32(&CGU_PERI, CGU_I2SOUT_APB_CLOCK_ENABLE);
I2SOUT_CONTROL = (1<<6) | (1<<3); /* enable dma, stereo */
audiohw_preinit();
sink_set_freq(HW_SAMPR_DEFAULT);
}
#ifdef HAVE_PCM_DMA_ADDRESS #ifdef HAVE_PCM_DMA_ADDRESS
void * pcm_dma_addr(void *addr) void * pcm_dma_addr(void *addr)
{ {
@ -210,6 +201,22 @@ void * pcm_dma_addr(void *addr)
} }
#endif #endif
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/**************************************************************************** /****************************************************************************
** Recording DMA transfer ** Recording DMA transfer

View file

@ -25,6 +25,8 @@
#include "dma-imx233.h" #include "dma-imx233.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "audioout-imx233.h" #include "audioout-imx233.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
struct pcm_dma_command_t struct pcm_dma_command_t
{ {
@ -47,7 +49,7 @@ static const void *dac_buf; /* current buffer */
static size_t dac_size; /* remaining size */ static size_t dac_size; /* remaining size */
/* for both recording and playback: maximum transfer size, see /* for both recording and playback: maximum transfer size, see
* pcm_dma_apply_settings */ * sink_set_sampr */
static size_t dma_max_size = CACHEALIGN_UP(1600); static size_t dma_max_size = CACHEALIGN_UP(1600);
enum enum
@ -110,33 +112,33 @@ void INT_DAC_ERROR(void)
imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC); imx233_dma_clear_channel_interrupt(APB_AUDIO_DAC);
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
if(dac_locked++ == 0) if(dac_locked++ == 0)
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, false); imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, false);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if(--dac_locked == 0) if(--dac_locked == 0)
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true); imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true);
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
/* do not interrupt the current transaction because resetting the dma /* do not interrupt the current transaction because resetting the dma
* would halt the DAC and clearing RUN causes sound havoc so simply * would halt the DAC and clearing RUN causes sound havoc so simply
* wait for the end of transfer */ * wait for the end of transfer */
pcm_play_lock(); sink_lock();
dac_buf = NULL; dac_buf = NULL;
dac_size = 0; dac_size = 0;
dac_state = DAC_STOP_PENDING; dac_state = DAC_STOP_PENDING;
pcm_play_unlock(); sink_unlock();
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
pcm_play_lock(); sink_lock();
/* update pending buffer */ /* update pending buffer */
dac_buf = addr; dac_buf = addr;
dac_size = size; dac_size = size;
@ -145,15 +147,10 @@ void pcm_play_dma_start(const void *addr, size_t size)
play(); play();
else else
dac_state = DAC_PLAYING; dac_state = DAC_PLAYING;
pcm_play_unlock(); sink_unlock();
} }
void pcm_play_dma_init(void) static void sink_dma_postinit(void)
{
audiohw_preinit();
}
void pcm_play_dma_postinit(void)
{ {
audiohw_postinit(); audiohw_postinit();
imx233_icoll_enable_interrupt(INT_SRC_DAC_DMA, true); imx233_icoll_enable_interrupt(INT_SRC_DAC_DMA, true);
@ -162,18 +159,35 @@ void pcm_play_dma_postinit(void)
imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true); imx233_dma_enable_channel_interrupt(APB_AUDIO_DAC, true);
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
pcm_play_lock(); sink_lock();
/* update frequency */ /* update frequency */
audiohw_set_frequency(pcm_fsel); audiohw_set_frequency(freq);
/* compute maximum transfer size: aim at ~1/100s stop time maximum, make sure /* compute maximum transfer size: aim at ~1/100s stop time maximum, make sure
* the resulting value is a multiple of cache line. At sample rate F we * the resulting value is a multiple of cache line. At sample rate F we
* transfer two samples (2 x 2 bytes) F times per second = 4F b/s */ * transfer two samples (2 x 2 bytes) F times per second = 4F b/s */
dma_max_size = CACHEALIGN_UP(4 * pcm_sampr / 100); dma_max_size = CACHEALIGN_UP(4 * hw_freq_sampr[freq] / 100);
pcm_play_unlock(); sink_unlock();
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = audiohw_preinit,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/* /*
* Recording * Recording
*/ */

View file

@ -26,6 +26,7 @@
#include "sdma-imx31.h" #include "sdma-imx31.h"
#include "mmu-imx31.h" #include "mmu-imx31.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
#define DMA_PLAY_CH_NUM 2 #define DMA_PLAY_CH_NUM 2
#define DMA_REC_CH_NUM 1 #define DMA_REC_CH_NUM 1
@ -112,12 +113,12 @@ static void play_dma_callback(void)
} }
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
++dma_play_data.locked; ++dma_play_data.locked;
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if (--dma_play_data.locked == 0 && dma_play_data.state != 0) if (--dma_play_data.locked == 0 && dma_play_data.state != 0)
{ {
@ -131,12 +132,12 @@ void pcm_play_unlock(void)
} }
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
audiohw_set_frequency(pcm_fsel); audiohw_set_frequency(freq);
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
/* Init DMA channel information */ /* Init DMA channel information */
sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd); sdma_channel_init(DMA_PLAY_CH_NUM, &dma_play_cd, &dma_play_bd);
@ -146,11 +147,6 @@ void pcm_play_dma_init(void)
audiohw_init(); audiohw_init();
} }
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
static void play_start_pcm(void) static void play_start_pcm(void)
{ {
/* Stop transmission (if in progress) */ /* Stop transmission (if in progress) */
@ -200,7 +196,7 @@ static void play_stop_pcm(void)
dma_play_data.callback_pending = 0; dma_play_data.callback_pending = 0;
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
sdma_channel_stop(DMA_PLAY_CH_NUM); sdma_channel_stop(DMA_PLAY_CH_NUM);
@ -218,7 +214,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
play_start_dma(addr, size); play_start_dma(addr, size);
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
sdma_channel_stop(DMA_PLAY_CH_NUM); sdma_channel_stop(DMA_PLAY_CH_NUM);
play_stop_pcm(); play_stop_pcm();
@ -229,6 +225,23 @@ void * pcm_dma_addr(void *addr)
return (void *)addr_virt_to_phys((unsigned long)addr); return (void *)addr_virt_to_phys((unsigned long)addr);
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
static struct buffer_descriptor dma_rec_bd NOCACHEBSS_ATTR; static struct buffer_descriptor dma_rec_bd NOCACHEBSS_ATTR;

View file

@ -28,6 +28,7 @@
#include "i2s.h" #include "i2s.h"
#include "pcm.h" #include "pcm.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
struct dma_data struct dma_data
{ {
@ -62,7 +63,7 @@ struct dma_data dma_play_data SHAREDBSS_ATTR =
.state = 0 .state = 0
}; };
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
DAVC = 0x0; /* Digital Volume = max */ DAVC = 0x0; /* Digital Volume = max */
#ifdef COWON_D2 #ifdef COWON_D2
@ -89,12 +90,7 @@ void pcm_play_dma_init(void)
#endif #endif
} }
void pcm_play_dma_postinit(void) static void sink_set_freq(uint16_t freq)
{
audiohw_postinit();
}
void pcm_dma_apply_settings(void)
{ {
} }
@ -125,7 +121,7 @@ static void play_stop_pcm(void)
dma_play_data.state = 0; dma_play_data.state = 0;
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
dma_play_data.p_r = addr; dma_play_data.p_r = addr;
dma_play_data.size = size; dma_play_data.size = size;
@ -140,7 +136,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
play_start_pcm(); play_start_pcm();
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
play_stop_pcm(); play_stop_pcm();
dma_play_data.size = 0; dma_play_data.size = 0;
@ -149,7 +145,7 @@ void pcm_play_dma_stop(void)
#endif #endif
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
int status = disable_fiq_save(); int status = disable_fiq_save();
@ -161,7 +157,7 @@ void pcm_play_lock(void)
restore_fiq(status); restore_fiq(status);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
int status = disable_fiq_save(); int status = disable_fiq_save();
@ -173,6 +169,23 @@ void pcm_play_unlock(void)
restore_fiq(status); restore_fiq(status);
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
/* TODO: implement */ /* TODO: implement */
void pcm_rec_dma_init(void) void pcm_rec_dma_init(void)

View file

@ -27,6 +27,7 @@
#include "pcm.h" #include "pcm.h"
#include "pcm_sampr.h" #include "pcm_sampr.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
/** DMA **/ /** DMA **/
@ -89,10 +90,12 @@ static struct dma_data dma_play_data IBSS_ATTR =
.state = 0 .state = 0
}; };
void pcm_dma_apply_settings(void) /* DMA status cannot be viewed from outside code in control because that can
{ * clear the interrupt from outside the handler and prevent the handler from
audiohw_set_frequency(pcm_fsel); * from being called. Split up transfers to a reasonable size that is good as
} * a timer and peaking yet still keeps the FIQ count low.
*/
static uint16_t max_dma_chunk_size;
#if defined(CPU_PP502x) #if defined(CPU_PP502x)
/* 16-bit, L-R packed into 32 bits with left in the least significant halfword */ /* 16-bit, L-R packed into 32 bits with left in the least significant halfword */
@ -102,12 +105,6 @@ void pcm_dma_apply_settings(void)
#define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \ #define DMA_PLAY_CONFIG ((DMA_REQ_IIS << DMA_CMD_REQ_ID_POS) | \
DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \ DMA_CMD_RAM_TO_PER | DMA_CMD_SINGLE | \
DMA_CMD_WAIT_REQ | DMA_CMD_INTR) DMA_CMD_WAIT_REQ | DMA_CMD_INTR)
/* DMA status cannot be viewed from outside code in control because that can
* clear the interrupt from outside the handler and prevent the handler from
* from being called. Split up transfers to a reasonable size that is good as
* a timer and peaking yet still keeps the FIQ count low.
*/
#define MAX_DMA_CHUNK_SIZE (pcm_curr_sampr >> 6) /* ~1/256 seconds */
static inline void dma_tx_init(void) static inline void dma_tx_init(void)
{ {
@ -145,9 +142,9 @@ static inline unsigned long dma_tx_buf_prepare(const void *addr)
static inline void dma_tx_start(bool begin) static inline void dma_tx_start(bool begin)
{ {
size_t size = MAX_DMA_CHUNK_SIZE; size_t size = max_dma_chunk_size;
/* Not at least MAX_DMA_CHUNK_SIZE left or there would be less /* Not at least max_dma_chunk_size left or there would be less
* than a FIFO's worth of data after this transfer? */ * than a FIFO's worth of data after this transfer? */
if (size + 16*4 > dma_play_data.size) if (size + 16*4 > dma_play_data.size)
size = dma_play_data.size; size = dma_play_data.size;
@ -430,10 +427,15 @@ void fiq_playback(void)
#endif /* ASM / C selection */ #endif /* ASM / C selection */
#endif /* CPU_PP502x */ #endif /* CPU_PP502x */
static void sink_set_freq(uint16_t freq) {
max_dma_chunk_size = hw_freq_sampr[freq] >> 6;
audiohw_set_frequency(freq);
}
/* For the locks, FIQ must be disabled because the handler manipulates /* For the locks, FIQ must be disabled because the handler manipulates
IISCONFIG and the operation is not atomic - dual core support IISCONFIG and the operation is not atomic - dual core support
will require other measures */ will require other measures */
void pcm_play_lock(void) static void sink_lock(void)
{ {
int status = disable_fiq_save(); int status = disable_fiq_save();
@ -444,7 +446,7 @@ void pcm_play_lock(void)
restore_fiq(status); restore_fiq(status);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
int status = disable_fiq_save(); int status = disable_fiq_save();
@ -455,14 +457,14 @@ void pcm_play_unlock(void)
restore_fiq(status); restore_fiq(status);
} }
static void play_start_pcm(void) static void sink_start_pcm(void)
{ {
fiq_function = fiq_playback; fiq_function = fiq_playback;
dma_play_data.state = 1; dma_play_data.state = 1;
dma_tx_start(true); dma_tx_start(true);
} }
static void play_stop_pcm(void) static void sink_stop_pcm(void)
{ {
dma_tx_stop(); dma_tx_stop();
@ -472,9 +474,11 @@ static void play_stop_pcm(void)
dma_play_data.state = 0; dma_play_data.state = 0;
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_stop(void);
static void sink_dma_start(const void *addr, size_t size)
{ {
pcm_play_dma_stop(); sink_dma_stop();
#if NUM_CORES > 1 #if NUM_CORES > 1
/* This will become more important later - and different ! */ /* This will become more important later - and different ! */
@ -485,13 +489,13 @@ void pcm_play_dma_start(const void *addr, size_t size)
dma_play_data.addr = dma_tx_buf_prepare(addr); dma_play_data.addr = dma_tx_buf_prepare(addr);
dma_play_data.size = size; dma_play_data.size = size;
play_start_pcm(); sink_start_pcm();
} }
/* Stops the DMA transfer and interrupt */ /* Stops the DMA transfer and interrupt */
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
play_stop_pcm(); sink_stop_pcm();
dma_play_data.addr = 0; dma_play_data.addr = 0;
dma_play_data.size = 0; dma_play_data.size = 0;
#if NUM_CORES > 1 #if NUM_CORES > 1
@ -499,7 +503,7 @@ void pcm_play_dma_stop(void)
#endif #endif
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
/* Initialize default register values. */ /* Initialize default register values. */
audiohw_init(); audiohw_init();
@ -509,10 +513,22 @@ void pcm_play_dma_init(void)
IISCONFIG |= IIS_TXFIFOEN; IISCONFIG |= IIS_TXFIFOEN;
} }
void pcm_play_dma_postinit(void) struct pcm_sink builtin_pcm_sink = {
{ .caps = {
audiohw_postinit(); .samprs = hw_freq_sampr,
} .num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/**************************************************************************** /****************************************************************************
** Recording DMA transfer ** Recording DMA transfer

View file

@ -28,11 +28,12 @@
#include "audiohw.h" #include "audiohw.h"
#include "sound.h" #include "sound.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
static int locked = 0; static int locked = 0;
/* Mask the DMA interrupt */ /* Mask the DMA interrupt */
void pcm_play_lock(void) static void sink_lock(void)
{ {
if (++locked == 1) if (++locked == 1)
{ {
@ -43,7 +44,7 @@ void pcm_play_lock(void)
} }
/* Unmask the DMA interrupt if enabled */ /* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if(--locked == 0) if(--locked == 0)
{ {
@ -53,7 +54,7 @@ void pcm_play_unlock(void)
} }
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
HDMA_CON0 = 0x00; HDMA_CON0 = 0x00;
HDMA_ISR = 0x00; HDMA_ISR = 0x00;
@ -105,10 +106,10 @@ static void hdma_i2s_transfer(const void *addr, size_t size)
(1<<0)); /* hardware trigger DMA mode */ (1<<0)); /* hardware trigger DMA mode */
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
/* Stop any DMA in progress */ /* Stop any DMA in progress */
pcm_play_dma_stop(); sink_dma_stop();
/* kick in DMA transfer */ /* kick in DMA transfer */
hdma_i2s_transfer(addr, size); hdma_i2s_transfer(addr, size);
@ -225,7 +226,7 @@ static void set_codec_freq(unsigned int freq)
} }
#endif #endif
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
/* unmask HDMA interrupt in INTC */ /* unmask HDMA interrupt in INTC */
INTC_IMR |= IRQ_ARM_HDMA; INTC_IMR |= IRQ_ARM_HDMA;
@ -236,18 +237,13 @@ void pcm_play_dma_init(void)
i2s_init(); i2s_init();
} }
void pcm_play_dma_postinit(void) static void sink_set_freq(uint16_t freq)
{
audiohw_postinit();
}
void pcm_dma_apply_settings(void)
{ {
#ifdef CODEC_SLAVE #ifdef CODEC_SLAVE
set_codec_freq(pcm_fsel); set_codec_freq(freq);
#endif #endif
audiohw_set_frequency(pcm_fsel); audiohw_set_frequency(freq);
} }
/* audio DMA ISR called when chunk from callers buffer has been transfered */ /* audio DMA ISR called when chunk from callers buffer has been transfered */
@ -263,6 +259,23 @@ void INT_HDMA(void)
} }
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/**************************************************************************** /****************************************************************************
** Recording DMA transfer ** Recording DMA transfer
**/ **/

View file

@ -26,6 +26,7 @@
#include "sound.h" #include "sound.h"
#include "file.h" #include "file.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
/* PCM interrupt routine lockout */ /* PCM interrupt routine lockout */
static struct static struct
@ -48,20 +49,20 @@ static struct
void fiq_handler(void) __attribute__((interrupt ("FIQ"))); void fiq_handler(void) __attribute__((interrupt ("FIQ")));
/* Mask the DMA interrupt */ /* Mask the DMA interrupt */
void pcm_play_lock(void) static void sink_lock(void)
{ {
if (++dma_play_lock.locked == 1) if (++dma_play_lock.locked == 1)
bitset32(&INTMSK, DMA2_MASK); bitset32(&INTMSK, DMA2_MASK);
} }
/* Unmask the DMA interrupt if enabled */ /* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if (--dma_play_lock.locked == 0) if (--dma_play_lock.locked == 0)
bitclr32(&INTMSK, dma_play_lock.state); bitclr32(&INTMSK, dma_play_lock.state);
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
/* There seem to be problems when changing the IIS interface configuration /* There seem to be problems when changing the IIS interface configuration
* when a clock is not present. * when a clock is not present.
@ -94,14 +95,9 @@ void pcm_play_dma_init(void)
bitset32(&INTMOD, DMA2_MASK); bitset32(&INTMOD, DMA2_MASK);
} }
void pcm_play_dma_postinit(void) static void sink_set_freq(uint16_t freq)
{ {
audiohw_postinit(); audiohw_set_frequency(freq);
}
void pcm_dma_apply_settings(void)
{
audiohw_set_frequency(pcm_fsel);
} }
/* Connect the DMA and start filling the FIFO */ /* Connect the DMA and start filling the FIFO */
@ -158,7 +154,7 @@ static void play_stop_pcm(void)
IISCON &= ~(1<<0); IISCON &= ~(1<<0);
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
/* Enable the IIS clock */ /* Enable the IIS clock */
bitset32(&CLKCON, 1<<17); bitset32(&CLKCON, 1<<17);
@ -187,7 +183,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
} }
/* Promptly stop DMA transfers and stop IIS */ /* Promptly stop DMA transfers and stop IIS */
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
play_stop_pcm(); play_stop_pcm();
@ -219,3 +215,20 @@ void fiq_handler(void)
pcm_play_dma_status_callback(PCM_DMAST_STARTED); pcm_play_dma_status_callback(PCM_DMAST_STARTED);
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -32,11 +32,12 @@
#include "dma-target.h" #include "dma-target.h"
#include "mmu-arm.h" #include "mmu-arm.h"
#include "cpucache-arm.h" #include "cpucache-arm.h"
#include "pcm_sink.h"
/* Driver for the IIS/PCM part of the s5l8700 using DMA /* Driver for the IIS/PCM part of the s5l8700 using DMA
Notes: Notes:
- pcm_play_dma_stop is untested, not sure if implemented the right way - sink_dma_stop is untested, not sure if implemented the right way
- recording is not implemented - recording is not implemented
*/ */
@ -83,7 +84,7 @@ static const struct div_entry {
}; };
/* Mask the DMA interrupt */ /* Mask the DMA interrupt */
void pcm_play_lock(void) static void sink_lock(void)
{ {
if (locked++ == 0) { if (locked++ == 0) {
INTMSK &= ~(1 << 10); INTMSK &= ~(1 << 10);
@ -91,7 +92,7 @@ void pcm_play_lock(void)
} }
/* Unmask the DMA interrupt if enabled */ /* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if (--locked == 0) { if (--locked == 0) {
INTMSK |= (1 << 10); INTMSK |= (1 << 10);
@ -141,7 +142,7 @@ void INT_DMA(void)
} }
void pcm_play_dma_start(const void* addr, size_t size) static void sink_dma_start(const void* addr, size_t size)
{ {
/* DMA channel on */ /* DMA channel on */
nextbuf = addr; nextbuf = addr;
@ -161,7 +162,7 @@ void pcm_play_dma_start(const void* addr, size_t size)
(0 << 0); /* 0 = LRCK on */ (0 << 0); /* 0 = LRCK on */
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
/* DMA channel off */ /* DMA channel off */
DMACOM0 = 5; DMACOM0 = 5;
@ -195,7 +196,7 @@ static void pcm_dma_set_freq(enum hw_freq_indexes idx)
(div.cdiv - 1); /* MCLK_DIV_VAL */ (div.cdiv - 1); /* MCLK_DIV_VAL */
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
/* configure IIS pins */ /* configure IIS pins */
#ifdef IPOD_NANO2G #ifdef IPOD_NANO2G
@ -252,15 +253,10 @@ void pcm_play_dma_init(void)
audiohw_preinit(); audiohw_preinit();
} }
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
}
/* set the configured PCM frequency */ /* set the configured PCM frequency */
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
pcm_dma_set_freq(pcm_fsel); pcm_dma_set_freq(hw_freq_sampr[freq]);
} }
#ifdef HAVE_PCM_DMA_ADDRESS #ifdef HAVE_PCM_DMA_ADDRESS
@ -272,6 +268,22 @@ void * pcm_dma_addr(void *addr)
} }
#endif #endif
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/**************************************************************************** /****************************************************************************
** Recording DMA transfer ** Recording DMA transfer

View file

@ -31,6 +31,7 @@
#include "pcm_sampr.h" #include "pcm_sampr.h"
#include "pcm-target.h" #include "pcm-target.h"
#include "dma-s5l8702.h" #include "dma-s5l8702.h"
#include "pcm_sink.h"
/* DMA configuration */ /* DMA configuration */
@ -86,14 +87,14 @@ static int active_dblbuf;
size_t pcm_remaining; size_t pcm_remaining;
/* Mask the DMA interrupt */ /* Mask the DMA interrupt */
void pcm_play_lock(void) static void sink_lock(void)
{ {
if (locked++ == 0) if (locked++ == 0)
dmac_ch_lock_int(&dma_play_ch); dmac_ch_lock_int(&dma_play_ch);
} }
/* Unmask the DMA interrupt if enabled */ /* Unmask the DMA interrupt if enabled */
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if (--locked == 0) if (--locked == 0)
dmac_ch_unlock_int(&dma_play_ch); dmac_ch_unlock_int(&dma_play_ch);
@ -141,30 +142,29 @@ static void dma_play_callback(void *cb_data)
pcm_play_dma_status_callback(PCM_DMAST_STARTED); pcm_play_dma_status_callback(PCM_DMAST_STARTED);
} }
void pcm_play_dma_start(const void* addr, size_t size) static void sink_dma_stop(void)
{ {
pcm_play_dma_stop(); dmac_ch_stop(&dma_play_ch);
I2STXCOM = 0xa;
}
static void sink_dma_start(const void* addr, size_t size)
{
sink_dma_stop();
pcm_remaining = size; pcm_remaining = size;
I2STXCOM = 0xe; I2STXCOM = 0xe;
dma_play_callback((void*)addr); dma_play_callback((void*)addr);
} }
void pcm_play_dma_stop(void)
{
dmac_ch_stop(&dma_play_ch);
I2STXCOM = 0xa;
}
/* MCLK = 12MHz (MCLKDIV2=1), [CS42L55 DS, s4.8] */ /* MCLK = 12MHz (MCLKDIV2=1), [CS42L55 DS, s4.8] */
#define MCLK_FREQ 12000000 #define MCLK_FREQ 12000000
/* set the configured PCM frequency */ /* set the configured PCM frequency */
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
static uint16_t last_clkcon3l = 0; static uint16_t last_clkcon3l = 0;
uint16_t clkcon3l; uint16_t clkcon3l;
int fsel;
/* For unknown reasons, s5l8702 I2S controller does not synchronize /* For unknown reasons, s5l8702 I2S controller does not synchronize
* with CS42L55 at 32000 Hz. To fix it, the CODEC is configured with * with CS42L55 at 32000 Hz. To fix it, the CODEC is configured with
@ -172,12 +172,11 @@ void pcm_dma_apply_settings(void)
* obtaining 32 KHz in LRCK controller input and 8 MHz in SCLK input. * obtaining 32 KHz in LRCK controller input and 8 MHz in SCLK input.
* OF uses this trick. * OF uses this trick.
*/ */
if (pcm_fsel == HW_FREQ_32) { if (freq == HW_FREQ_32) {
fsel = HW_FREQ_48; freq = HW_FREQ_48;
clkcon3l = 0x3028; /* PLL2 / 3 / 9 -> 8 MHz */ clkcon3l = 0x3028; /* PLL2 / 3 / 9 -> 8 MHz */
} }
else { else {
fsel = pcm_fsel;
clkcon3l = 0; /* OSC0 -> 12 MHz */ clkcon3l = 0; /* OSC0 -> 12 MHz */
} }
@ -192,12 +191,12 @@ void pcm_dma_apply_settings(void)
} }
/* configure I2S clock ratio */ /* configure I2S clock ratio */
I2SCLKDIV = MCLK_FREQ / hw_freq_sampr[fsel]; I2SCLKDIV = MCLK_FREQ / hw_freq_sampr[freq];
/* select CS42L55 sample rate */ /* select CS42L55 sample rate */
audiohw_set_frequency(fsel); audiohw_set_frequency(freq);
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
PWRCON(1) &= ~(1 << 7); PWRCON(1) &= ~(1 << 7);
@ -207,12 +206,7 @@ void pcm_play_dma_init(void)
I2SCLKCON = 1; I2SCLKCON = 1;
audiohw_preinit(); audiohw_preinit();
pcm_dma_apply_settings(); sink_set_freq(HW_FREQ_DEFAULT);
}
void pcm_play_dma_postinit(void)
{
audiohw_postinit();
} }
#ifdef HAVE_PCM_DMA_ADDRESS #ifdef HAVE_PCM_DMA_ADDRESS
@ -222,6 +216,22 @@ void * pcm_dma_addr(void *addr)
} }
#endif #endif
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
/**************************************************************************** /****************************************************************************
** Recording DMA transfer ** Recording DMA transfer

View file

@ -20,37 +20,57 @@
****************************************************************************/ ****************************************************************************/
#include "pcm.h" #include "pcm.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{
(void)freq;
}
static void sink_dma_init(void)
{ {
} }
void pcm_play_dma_init(void) static void sink_dma_postinit(void)
{ {
} }
void pcm_play_dma_postinit(void) static void sink_dma_start(const void *addr, size_t size)
{
}
void pcm_play_dma_start(const void *addr, size_t size)
{ {
(void)addr; (void)addr;
(void)size; (void)size;
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
void pcm_rec_dma_init(void) void pcm_rec_dma_init(void)
{ {

View file

@ -28,13 +28,14 @@
#include "dsp-target.h" #include "dsp-target.h"
#include "dsp/ipc.h" #include "dsp/ipc.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is /* This is global to save some latency when pcm_play_dma_get_peak_buffer is
* called. * called.
*/ */
static const void *start; static const void *start;
void pcm_play_dma_postinit(void) static void sink_dma_postinit(void)
{ {
/* Configure clock divider */ /* Configure clock divider */
tsc2100_writereg(CONTROL_PAGE2, TSPP1_ADDRESS, 0x1120); tsc2100_writereg(CONTROL_PAGE2, TSPP1_ADDRESS, 0x1120);
@ -45,7 +46,7 @@ void pcm_play_dma_postinit(void)
audiohw_postinit(); audiohw_postinit();
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
IO_INTC_IRQ0 = INTR_IRQ0_IMGBUF; IO_INTC_IRQ0 = INTR_IRQ0_IMGBUF;
bitset16(&IO_INTC_EINT0, INTR_EINT0_IMGBUF); bitset16(&IO_INTC_EINT0, INTR_EINT0_IMGBUF);
@ -67,15 +68,15 @@ void pcm_play_dma_init(void)
dsp_wake(); dsp_wake();
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
audiohw_set_frequency(pcm_fsel); audiohw_set_frequency(freq);
} }
/* Note that size is actually limited to the size of a short right now due to /* Note that size is actually limited to the size of a short right now due to
* the implementation on the DSP side (and the way that we access it) * the implementation on the DSP side (and the way that we access it)
*/ */
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START; unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START;
/* Initialize codec. */ /* Initialize codec. */
@ -87,18 +88,18 @@ void pcm_play_dma_start(const void *addr, size_t size)
dsp_wake(); dsp_wake();
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
DSP_(_dma0_stopped)=1; DSP_(_dma0_stopped)=1;
dsp_wake(); dsp_wake();
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
} }
@ -156,4 +157,20 @@ void DSPHINT(void)
DEBUGF("DSP: %s", buffer); DEBUGF("DSP: %s", buffer);
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -29,6 +29,7 @@
#include "dsp/ipc.h" #include "dsp/ipc.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "dma-target.h" #include "dma-target.h"
#include "pcm_sink.h"
/* This is global to save some latency when pcm_play_dma_get_peak_buffer is /* This is global to save some latency when pcm_play_dma_get_peak_buffer is
* called. * called.
@ -36,12 +37,7 @@
static const void *start; static const void *start;
static int dma_channel; static int dma_channel;
void pcm_play_dma_postinit(void) static void sink_dma_init(void)
{
audiohw_postinit();
}
void pcm_play_dma_init(void)
{ {
/* GIO16 is DSP/AIC3X CLK */ /* GIO16 is DSP/AIC3X CLK */
IO_GIO_FSEL0 &= 0x3FFF; IO_GIO_FSEL0 &= 0x3FFF;
@ -74,15 +70,15 @@ void pcm_play_dma_init(void)
dsp_wake(); dsp_wake();
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
audiohw_set_frequency(pcm_fsel); audiohw_set_frequency(freq);
} }
/* Note that size is actually limited to the size of a short right now due to /* Note that size is actually limited to the size of a short right now due to
* the implementation on the DSP side (and the way that we access it) * the implementation on the DSP side (and the way that we access it)
*/ */
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START; unsigned long sdem_addr=(unsigned long)addr - CONFIG_SDRAM_START;
/* Initialize codec. */ /* Initialize codec. */
@ -94,18 +90,18 @@ void pcm_play_dma_start(const void *addr, size_t size)
dsp_wake(); dsp_wake();
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
DSP_(_dma0_stopped)=1; DSP_(_dma0_stopped)=1;
dsp_wake(); dsp_wake();
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
} }
@ -163,4 +159,20 @@ void DSPHINT(void)
DEBUGF("DSP: %s", buffer); DEBUGF("DSP: %s", buffer);
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -29,6 +29,7 @@
#include "spdif.h" #include "spdif.h"
#endif #endif
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
#define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \ #define IIS_PLAY_DEFPARM ( (freq_ent[FPARM_CLOCKSEL] << 12) | \
(IIS_PLAY & (7 << 8)) | \ (IIS_PLAY & (7 << 8)) | \
@ -142,12 +143,12 @@ static void iis_play_reset_if_playback(bool if_playback)
/* This clears the reset bit to enable monitoring immediately if monitoring /* This clears the reset bit to enable monitoring immediately if monitoring
recording sources or always if playback is in progress - we might be recording sources or always if playback is in progress - we might be
switching samplerates on the fly */ switching samplerates on the fly */
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
int level = set_irq_level(DMA_IRQ_LEVEL); int level = set_irq_level(DMA_IRQ_LEVEL);
/* remember table entry */ /* remember table entry */
freq_ent = pcm_freq_parms[pcm_fsel]; freq_ent = pcm_freq_parms[freq];
/* Reprogramming bits 15-12 requires FIFO to be in a reset /* Reprogramming bits 15-12 requires FIFO to be in a reset
condition - Users Manual 17-8, Note 11 */ condition - Users Manual 17-8, Note 11 */
@ -159,7 +160,7 @@ void pcm_dma_apply_settings(void)
IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET; IIS_PLAY = IIS_PLAY_DEFPARM | IIS_FIFO_RESET;
restore_irq(level); restore_irq(level);
audiohw_set_frequency(pcm_fsel); audiohw_set_frequency(freq);
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM); coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
level = set_irq_level(DMA_IRQ_LEVEL); level = set_irq_level(DMA_IRQ_LEVEL);
@ -170,11 +171,11 @@ void pcm_dma_apply_settings(void)
PDOR3 = 0; /* Kick FIFO out of reset by writing to it */ PDOR3 = 0; /* Kick FIFO out of reset by writing to it */
restore_irq(level); restore_irq(level);
} /* pcm_dma_apply_settings */ } /* sink_set_sampr */
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
freq_ent = pcm_freq_parms[pcm_fsel]; freq_ent = pcm_freq_parms[HW_FREQ_DEFAULT];
AUDIOGLOB = AUDIOGLOB_DEFPARM; AUDIOGLOB = AUDIOGLOB_DEFPARM;
DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */ DIVR0 = 54; /* DMA0 is mapped into vector 54 in system.c */
@ -195,15 +196,15 @@ void pcm_play_dma_init(void)
audio_input_mux(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK); audio_input_mux(AUDIO_SRC_PLAYBACK, SRCF_PLAYBACK);
audiohw_set_frequency(pcm_fsel); audiohw_set_frequency(HW_FREQ_DEFAULT);
coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM); coldfire_set_pllcr_audio_bits(PLLCR_SET_AUDIO_BITS_DEFPARM);
#if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT) #if defined(HAVE_SPDIF_REC) || defined(HAVE_SPDIF_OUT)
spdif_init(); spdif_init();
#endif #endif
} /* pcm_play_dma_init */ } /* sink_dma_init */
void pcm_play_dma_postinit(void) void sink_dma_postinit(void)
{ {
audiohw_postinit(); audiohw_postinit();
iis_play_reset(); iis_play_reset();
@ -223,23 +224,35 @@ static struct dma_lock dma_play_lock =
.state = (1 << 14) /* bit 14 is DMA0 */ .state = (1 << 14) /* bit 14 is DMA0 */
}; };
void pcm_play_lock(void) static void sink_lock(void)
{ {
if (++dma_play_lock.locked == 1) if (++dma_play_lock.locked == 1)
coldfire_imr_mod(1 << 14, 1 << 14); coldfire_imr_mod(1 << 14, 1 << 14);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if (--dma_play_lock.locked == 0) if (--dma_play_lock.locked == 0)
coldfire_imr_mod(dma_play_lock.state, 1 << 14); coldfire_imr_mod(dma_play_lock.state, 1 << 14);
} }
/* Stops the DMA transfer and interrupt */
static void sink_dma_stop(void)
{
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
BCR0 = 0; /* No bytes remaining */
DSR0 = 1; /* Clear interrupt, errors, stop transfer */
iis_play_reset_if_playback(true);
dma_play_lock.state = (1 << 14);
} /* sink_dma_stop */
/* Set up the DMA transfer that kicks in when the audio FIFO gets empty */ /* Set up the DMA transfer that kicks in when the audio FIFO gets empty */
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
/* Stop any DMA in progress */ /* Stop any DMA in progress */
pcm_play_dma_stop(); sink_dma_stop();
/* Set up DMA transfer */ /* Set up DMA transfer */
SAR0 = (unsigned long)addr; /* Source address */ SAR0 = (unsigned long)addr; /* Source address */
@ -250,19 +263,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
DMA_SSIZE(DMA_SIZE_LINE) | DMA_START; DMA_SSIZE(DMA_SIZE_LINE) | DMA_START;
dma_play_lock.state = (0 << 14); dma_play_lock.state = (0 << 14);
} /* pcm_play_dma_start */ } /* sink_dma_start */
/* Stops the DMA transfer and interrupt */
void pcm_play_dma_stop(void)
{
and_l(~(DMA_EEXT | DMA_INT), &DCR0); /* per request and int OFF */
BCR0 = 0; /* No bytes remaining */
DSR0 = 1; /* Clear interrupt, errors, stop transfer */
iis_play_reset_if_playback(true);
dma_play_lock.state = (1 << 14);
} /* pcm_play_dma_stop */
/* DMA0 Interrupt is called when the DMA has finished transfering a chunk /* DMA0 Interrupt is called when the DMA has finished transfering a chunk
from the caller's buffer */ from the caller's buffer */
@ -301,6 +302,23 @@ void DMA0(void)
/* else inished playing */ /* else inished playing */
} /* DMA0 */ } /* DMA0 */
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
/**************************************************************************** /****************************************************************************
** Recording DMA transfer ** Recording DMA transfer

View file

@ -28,6 +28,8 @@
#include "debug.h" #include "debug.h"
#include "pcm.h" #include "pcm.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
extern JNIEnv *env_ptr; extern JNIEnv *env_ptr;
@ -133,23 +135,24 @@ Java_org_rockbox_RockboxPCM_nativeWrite(JNIEnv *env, jobject this,
return max_size - left; return max_size - left;
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
if (++audio_locked == 1) if (++audio_locked == 1)
lock_audio(); lock_audio();
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if (--audio_locked == 0) if (--audio_locked == 0)
unlock_audio(); unlock_audio();
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
(void)freq;
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
pcm_data_start = addr; pcm_data_start = addr;
pcm_data_size = size; pcm_data_size = size;
@ -160,7 +163,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
0); 0);
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
/* NOTE: due to how pcm_play_dma_complete_callback() works, this is /* NOTE: due to how pcm_play_dma_complete_callback() works, this is
* possibly called from nativeWrite(), i.e. another (host) thread * possibly called from nativeWrite(), i.e. another (host) thread
@ -171,7 +174,7 @@ void pcm_play_dma_stop(void)
stop_method); stop_method);
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
/* in order to have background music playing after leaving the activity, /* in order to have background music playing after leaving the activity,
* we need to allocate the PCM object from the Rockbox thread (the Activity * we need to allocate the PCM object from the Rockbox thread (the Activity
@ -194,7 +197,7 @@ void pcm_play_dma_init(void)
write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I"); write_method = e->GetMethodID(env_ptr, RockboxPCM_class, "write", "([BII)I");
} }
void pcm_play_dma_postinit(void) static void sink_dma_postinit(void)
{ {
} }
@ -213,6 +216,23 @@ void pcm_shutdown(void)
pthread_mutex_destroy(&audio_lock_mutex); pthread_mutex_destroy(&audio_lock_mutex);
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_org_rockbox_RockboxPCM_postVolumeChangedEvent(JNIEnv *env, Java_org_rockbox_RockboxPCM_postVolumeChangedEvent(JNIEnv *env,
jobject this, jobject this,

View file

@ -45,6 +45,7 @@
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sampr.h" #include "pcm_sampr.h"
#include "pcm_mixer.h" #include "pcm_mixer.h"
#include "pcm_sink.h"
#include <3ds/ndsp/ndsp.h> #include <3ds/ndsp/ndsp.h>
#include <3ds/ndsp/channel.h> #include <3ds/ndsp/channel.h>
@ -102,14 +103,14 @@ static inline bool is_in_audio_thread(int audio_thread_id)
return false; return false;
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
if (!is_in_audio_thread(_pcm_thread_id)) { if (!is_in_audio_thread(_pcm_thread_id)) {
RecursiveLock_Lock(&_pcm_lock_mtx); RecursiveLock_Lock(&_pcm_lock_mtx);
} }
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if (!is_in_audio_thread(_pcm_thread_id)) { if (!is_in_audio_thread(_pcm_thread_id)) {
RecursiveLock_Unlock(&_pcm_lock_mtx); RecursiveLock_Unlock(&_pcm_lock_mtx);
@ -188,13 +189,13 @@ void dsp_callback(void *const nul_) {
LightEvent_Signal(&_dsp_callback_event); LightEvent_Signal(&_dsp_callback_event);
} }
static void pcm_dma_apply_settings_nolock(void) static void sink_set_freq_nolock(uint16_t freq)
{ {
ndspChnReset(0); ndspChnReset(0);
ndspSetOutputMode(NDSP_OUTPUT_STEREO); ndspSetOutputMode(NDSP_OUTPUT_STEREO);
ndspChnSetRate(0, pcm_sampr); ndspChnSetRate(0, hw_freq_sampr[freq]);
ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16); ndspChnSetFormat(0, NDSP_FORMAT_STEREO_PCM16);
/* ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE); */ /* ndspChnSetInterp(0, NDSP_INTERP_POLYPHASE); */
/* ndspChnSetInterp(0, NDSP_INTERP_NONE); */ /* ndspChnSetInterp(0, NDSP_INTERP_NONE); */
@ -235,7 +236,7 @@ static void pcm_dma_apply_settings_nolock(void)
-1, /* run on any core */ false); -1, /* run on any core */ false);
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
_pcm_buffer = addr; _pcm_buffer = addr;
_pcm_buffer_size = size; _pcm_buffer_size = size;
@ -245,7 +246,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
RecursiveLock_Unlock(&_pcm_lock_mtx); RecursiveLock_Unlock(&_pcm_lock_mtx);
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
RecursiveLock_Lock(&_pcm_lock_mtx); RecursiveLock_Lock(&_pcm_lock_mtx);
ndspChnSetPaused(0, true); ndspChnSetPaused(0, true);
@ -303,7 +304,7 @@ unsigned long spdif_measure_frequency(void)
#endif /* HAVE_RECORDING */ #endif /* HAVE_RECORDING */
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
Result ndsp_init_res = ndspInit(); Result ndsp_init_res = ndspInit();
if (R_FAILED(ndsp_init_res)) { if (R_FAILED(ndsp_init_res)) {
@ -319,15 +320,15 @@ void pcm_play_dma_init(void)
LightEvent_Init(&_dsp_callback_event, RESET_ONESHOT); LightEvent_Init(&_dsp_callback_event, RESET_ONESHOT);
} }
void pcm_play_dma_postinit(void) static void sink_dma_postinit(void)
{ {
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
pcm_play_lock(); sink_lock();
pcm_dma_apply_settings_nolock(); sink_set_freq_nolock(freq);
pcm_play_unlock(); sink_unlock();
} }
void pcm_close_device(void) void pcm_close_device(void)
@ -357,3 +358,20 @@ void audiohw_close(void)
{ {
pcm_close_device(); pcm_close_device();
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -31,6 +31,8 @@
#include "panic.h" #include "panic.h"
#include "pcm.h" #include "pcm.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sampr.h"
#include "pcm_sink.h"
#include "sound/asound.h" #include "sound/asound.h"
#include "tinyalsa/asoundlib.h" #include "tinyalsa/asoundlib.h"
@ -187,26 +189,26 @@ static const unsigned int DEVICE = 0;
static struct pcm_config _config; static struct pcm_config _config;
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
TRACE; TRACE;
#ifdef DEBUG #ifdef DEBUG
/* /*
DEBUG pcm_play_dma_init: Access: 0x000009 DEBUG sink_dma_init: Access: 0x000009
DEBUG pcm_play_dma_init: Format[0]: 0x000044 DEBUG sink_dma_init: Format[0]: 0x000044
DEBUG pcm_play_dma_init: Format[1]: 0x000010 DEBUG sink_dma_init: Format[1]: 0x000010
DEBUG pcm_play_dma_init: Format: S16_LE DEBUG sink_dma_init: Format: S16_LE
DEBUG pcm_play_dma_init: Format: S24_LE DEBUG sink_dma_init: Format: S24_LE
DEBUG pcm_play_dma_init: Format: S20_3LE DEBUG sink_dma_init: Format: S20_3LE
DEBUG pcm_play_dma_init: Subformat: 0x000001 DEBUG sink_dma_init: Subformat: 0x000001
DEBUG pcm_play_dma_init: Rate: min = 8000Hz, max = 192000Hz DEBUG sink_dma_init: Rate: min = 8000Hz, max = 192000Hz
DEBUG pcm_play_dma_init: Channels: min = 2, max = 2 DEBUG sink_dma_init: Channels: min = 2, max = 2
DEBUG pcm_play_dma_init: Sample bits: min=16, max=32 DEBUG sink_dma_init: Sample bits: min=16, max=32
DEBUG pcm_play_dma_init: Period size: min=8, max=10922 DEBUG sink_dma_init: Period size: min=8, max=10922
DEBUG pcm_play_dma_init: Period count: min=3, max=128 DEBUG sink_dma_init: Period count: min=3, max=128
DEBUG pcm_play_dma_init: 0 mixer controls. DEBUG sink_dma_init: 0 mixer controls.
*/ */
struct pcm_params* params = pcm_params_get(CARD, DEVICE, PCM_OUT); struct pcm_params* params = pcm_params_get(CARD, DEVICE, PCM_OUT);
@ -310,7 +312,7 @@ void pcm_play_dma_init(void)
pcm_thread_run relies on this size match. See pcm_mixer.h. pcm_thread_run relies on this size match. See pcm_mixer.h.
*/ */
_config.channels = 2; _config.channels = 2;
_config.rate = pcm_sampr; _config.rate = hw_freq_sampr[HW_FREQ_DEFAULT];
_config.period_size = 256; _config.period_size = 256;
_config.period_count = 4; _config.period_count = 4;
_config.format = PCM_FORMAT_S16_LE; _config.format = PCM_FORMAT_S16_LE;
@ -337,7 +339,7 @@ void pcm_play_dma_init(void)
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
TRACE; TRACE;
@ -364,7 +366,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
pthread_mutex_unlock(&_dma_suspended_mtx); pthread_mutex_unlock(&_dma_suspended_mtx);
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
TRACE; TRACE;
@ -375,11 +377,11 @@ void pcm_play_dma_stop(void)
} }
/* Unessecary play locks before pcm_play_dma_postinit. */ /* Unessecary play locks before sink_dma_postinit. */
static int _play_lock_recursion_count = -10000; static int _play_lock_recursion_count = -10000;
void pcm_play_dma_postinit(void) static void sink_dma_postinit(void)
{ {
TRACE; TRACE;
@ -387,7 +389,7 @@ void pcm_play_dma_postinit(void)
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
TRACE; TRACE;
@ -402,7 +404,7 @@ void pcm_play_lock(void)
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
TRACE; TRACE;
@ -418,9 +420,9 @@ void pcm_play_unlock(void)
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
unsigned int rate = pcm_get_frequency(); unsigned int rate = hw_freq_sampr[freq];
DEBUGF("DEBUG %s: Current sample rate: %u, next sampe rate: %u.", __func__, _config.rate, rate); DEBUGF("DEBUG %s: Current sample rate: %u, next sampe rate: %u.", __func__, _config.rate, rate);
@ -450,3 +452,20 @@ void pcm_close_device(void)
pcm_close(_alsa_handle); pcm_close(_alsa_handle);
_alsa_handle = NULL; _alsa_handle = NULL;
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -48,6 +48,7 @@
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_mixer.h" #include "pcm_mixer.h"
#include "pcm_sampr.h" #include "pcm_sampr.h"
#include "pcm_sink.h"
#include "audiohw.h" #include "audiohw.h"
#include "pcm-alsa.h" #include "pcm-alsa.h"
#include "fixedpoint.h" #include "fixedpoint.h"
@ -122,7 +123,7 @@ void pcm_alsa_set_capture_device(const char *device)
} }
#endif #endif
static int set_hwparams(snd_pcm_t *handle) static int set_hwparams(snd_pcm_t *handle, unsigned long sampr)
{ {
int err; int err;
unsigned int srate; unsigned int srate;
@ -136,10 +137,10 @@ static int set_hwparams(snd_pcm_t *handle)
Note these are in FRAMES, and are sized to be about 8.5ms Note these are in FRAMES, and are sized to be about 8.5ms
for the buffer and 2.1ms for the period for the buffer and 2.1ms for the period
*/ */
if (pcm_sampr > SAMPR_96) { if (sampr > SAMPR_96) {
buffer_size = MIX_FRAME_SAMPLES * 4 * 4; buffer_size = MIX_FRAME_SAMPLES * 4 * 4;
period_size = MIX_FRAME_SAMPLES * 4; period_size = MIX_FRAME_SAMPLES * 4;
} else if (pcm_sampr > SAMPR_48) { } else if (sampr > SAMPR_48) {
buffer_size = MIX_FRAME_SAMPLES * 2 * 4; buffer_size = MIX_FRAME_SAMPLES * 2 * 4;
period_size = MIX_FRAME_SAMPLES * 2; period_size = MIX_FRAME_SAMPLES * 2;
} else { } else {
@ -176,17 +177,17 @@ static int set_hwparams(snd_pcm_t *handle)
goto error; goto error;
} }
/* set the stream rate */ /* set the stream rate */
srate = pcm_sampr; srate = sampr;
err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0); err = snd_pcm_hw_params_set_rate_near(handle, params, &srate, 0);
if (err < 0) if (err < 0)
{ {
logf("Rate %luHz not available for playback: %s", pcm_sampr, snd_strerror(err)); logf("Rate %luHz not available for playback: %s", sampr, snd_strerror(err));
goto error; goto error;
} }
real_sample_rate = srate; real_sample_rate = srate;
if (real_sample_rate != pcm_sampr) if (real_sample_rate != sampr)
{ {
logf("Rate doesn't match (requested %luHz, get %dHz)", pcm_sampr, real_sample_rate); logf("Rate doesn't match (requested %luHz, get %dHz)", sampr, real_sample_rate);
err = -EINVAL; err = -EINVAL;
goto error; goto error;
} }
@ -595,7 +596,7 @@ static void open_hwdev(const char *device, snd_pcm_stream_t mode)
atexit(alsadev_cleanup); atexit(alsadev_cleanup);
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
logf("PCM DMA Init"); logf("PCM DMA Init");
@ -606,48 +607,50 @@ void pcm_play_dma_init(void)
return; return;
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
pthread_mutex_lock(&pcm_mtx); pthread_mutex_lock(&pcm_mtx);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
pthread_mutex_unlock(&pcm_mtx); pthread_mutex_unlock(&pcm_mtx);
} }
static void pcm_dma_apply_settings_nolock(void) static void sink_set_freq_nolock(uint16_t freq)
{ {
logf("PCM DMA Settings %d %lu", last_sample_rate, pcm_sampr); unsigned int sampr = hw_freq_sampr[freq];
if (last_sample_rate != pcm_sampr) logf("PCM DMA Settings %d %lu", last_sample_rate, sampr);
if (last_sample_rate != sampr)
{ {
last_sample_rate = pcm_sampr; last_sample_rate = sampr;
#ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE #ifdef AUDIOHW_MUTE_ON_SRATE_CHANGE
audiohw_mute(true); audiohw_mute(true);
#endif #endif
snd_pcm_drop(handle); snd_pcm_drop(handle);
set_hwparams(handle); // FIXME: check return code? set_hwparams(handle, sampr); // FIXME: check return code?
set_swparams(handle); // FIXME: check return code? set_swparams(handle); // FIXME: check return code?
#if defined(HAVE_NWZ_LINUX_CODEC) #if defined(HAVE_NWZ_LINUX_CODEC)
/* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */ /* Sony NWZ linux driver uses a nonstandard mecanism to set the sampling rate */
audiohw_set_frequency(pcm_sampr); audiohw_set_frequency(sampr);
#endif #endif
/* (Will be unmuted by pcm resuming) */ /* (Will be unmuted by pcm resuming) */
} }
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
pcm_play_lock(); sink_lock();
pcm_dma_apply_settings_nolock(); sink_set_freq_nolock(freq);
pcm_play_unlock(); sink_unlock();
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
logf("PCM DMA stop (%d)", snd_pcm_state(handle)); logf("PCM DMA stop (%d)", snd_pcm_state(handle));
@ -660,10 +663,9 @@ void pcm_play_dma_stop(void)
#endif #endif
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
logf("PCM DMA start (%p %d)", addr, size); logf("PCM DMA start (%p %d)", addr, size);
pcm_dma_apply_settings_nolock();
pcm_data = addr; pcm_data = addr;
pcm_size = size; pcm_size = size;
@ -749,7 +751,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
} }
} }
void pcm_play_dma_postinit(void) static void sink_dma_postinit(void)
{ {
audiohw_postinit(); audiohw_postinit();
@ -768,15 +770,32 @@ unsigned int pcm_alsa_get_xruns(void)
return xruns; return xruns;
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
void pcm_rec_lock(void) void pcm_rec_lock(void)
{ {
pcm_play_lock(); sink_lock();
} }
void pcm_rec_unlock(void) void pcm_rec_unlock(void)
{ {
pcm_play_unlock(); sink_unlock();
} }
void pcm_rec_dma_init(void) void pcm_rec_dma_init(void)
@ -796,7 +815,6 @@ void pcm_rec_dma_close(void)
void pcm_rec_dma_start(void *start, size_t size) void pcm_rec_dma_start(void *start, size_t size)
{ {
logf("PCM REC DMA start (%p %d)", start, size); logf("PCM REC DMA start (%p %d)", start, size);
pcm_dma_apply_settings_nolock();
pcm_data_rec = start; pcm_data_rec = start;
pcm_size = size; pcm_size = size;

View file

@ -44,6 +44,7 @@
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sampr.h" #include "pcm_sampr.h"
#include "pcm_mixer.h" #include "pcm_mixer.h"
#include "pcm_sink.h"
/*#define LOGF_ENABLE*/ /*#define LOGF_ENABLE*/
#include "logf.h" #include "logf.h"
@ -57,6 +58,8 @@ extern const char *audiodev;
static int cvt_status = -1; static int cvt_status = -1;
static unsigned long pcm_sampr;
static const void *pcm_data; static const void *pcm_data;
static size_t pcm_data_size; static size_t pcm_data_size;
static size_t pcm_sample_bytes; static size_t pcm_sample_bytes;
@ -80,13 +83,13 @@ static SDL_AudioCVT cvt;
static int audio_locked = 0; static int audio_locked = 0;
static SDL_mutex *audio_lock; static SDL_mutex *audio_lock;
void pcm_play_lock(void) static void sink_lock(void)
{ {
if (++audio_locked == 1) if (++audio_locked == 1)
SDL_LockMutex(audio_lock); SDL_LockMutex(audio_lock);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
if (--audio_locked == 0) if (--audio_locked == 0)
SDL_UnlockMutex(audio_lock); SDL_UnlockMutex(audio_lock);
@ -97,8 +100,11 @@ void pcm_play_unlock(void)
#endif #endif
static void sdl_audio_callback(void *handle, Uint8 *stream, int len); static void sdl_audio_callback(void *handle, Uint8 *stream, int len);
static void pcm_dma_apply_settings_nolock(void)
static void sink_set_freq_nolock(uint16_t freq)
{ {
pcm_sampr = hw_freq_sampr[freq];
SDL_AudioSpec wanted_spec; SDL_AudioSpec wanted_spec;
wanted_spec.freq = pcm_sampr; wanted_spec.freq = pcm_sampr;
wanted_spec.format = AUDIO_S16SYS; wanted_spec.format = AUDIO_S16SYS;
@ -161,14 +167,14 @@ static void pcm_dma_apply_settings_nolock(void)
} }
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
pcm_play_lock(); sink_lock();
pcm_dma_apply_settings_nolock(); sink_set_freq_nolock(freq);
pcm_play_unlock(); sink_unlock();
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_start(const void *addr, size_t size)
{ {
pcm_data = addr; pcm_data = addr;
pcm_data_size = size; pcm_data_size = size;
@ -180,7 +186,7 @@ void pcm_play_dma_start(const void *addr, size_t size)
#endif #endif
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
#if SDL_MAJOR_VERSION > 1 #if SDL_MAJOR_VERSION > 1
SDL_PauseAudioDevice(pcm_devid, 1); SDL_PauseAudioDevice(pcm_devid, 1);
@ -397,7 +403,7 @@ unsigned long spdif_measure_frequency(void)
#endif /* HAVE_RECORDING */ #endif /* HAVE_RECORDING */
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
if (SDL_InitSubSystem(SDL_INIT_AUDIO)) if (SDL_InitSubSystem(SDL_INIT_AUDIO))
{ {
@ -435,6 +441,23 @@ void pcm_play_dma_init(void)
#endif #endif
} }
void pcm_play_dma_postinit(void) static void sink_dma_postinit(void)
{ {
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -26,14 +26,14 @@
#include "sound.h" #include "sound.h"
#include "pcm.h" #include "pcm.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
#include "jz4740.h" #include "jz4740.h"
/**************************************************************************** /****************************************************************************
** Playback DMA transfer ** Playback DMA transfer
**/ **/
void pcm_play_dma_postinit(void) static void sink_dma_postinit(void)
{ {
audiohw_postinit(); audiohw_postinit();
@ -47,7 +47,7 @@ void pcm_play_dma_postinit(void)
__aic_flush_fifo(); __aic_flush_fifo();
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
/* TODO */ /* TODO */
@ -57,10 +57,10 @@ void pcm_play_dma_init(void)
audiohw_init(); audiohw_init();
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
/* TODO */ /* TODO */
audiohw_set_frequency(pcm_sampr); audiohw_set_frequency(freq);
} }
static const void* playback_address; static const void* playback_address;
@ -135,21 +135,7 @@ void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void)
} }
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_stop(void)
{
pcm_play_dma_stop();
dma_enable();
set_dma(addr, size);
__aic_enable_transmit_dma();
__aic_enable_replay();
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
}
void pcm_play_dma_stop(void)
{ {
int flags = disable_irq_save(); int flags = disable_irq_save();
@ -163,8 +149,22 @@ void pcm_play_dma_stop(void)
restore_irq(flags); restore_irq(flags);
} }
static void sink_dma_start(const void *addr, size_t size)
{
sink_dma_stop();
dma_enable();
set_dma(addr, size);
__aic_enable_transmit_dma();
__aic_enable_replay();
REG_DMAC_DCCSR(DMA_AIC_TX_CHANNEL) |= DMAC_DCCSR_EN;
}
static unsigned int play_lock = 0; static unsigned int play_lock = 0;
void pcm_play_lock(void) static void sink_lock(void)
{ {
int flags = disable_irq_save(); int flags = disable_irq_save();
@ -174,7 +174,7 @@ void pcm_play_lock(void)
restore_irq(flags); restore_irq(flags);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
int flags = disable_irq_save(); int flags = disable_irq_save();
@ -189,6 +189,23 @@ void audiohw_close(void)
/* TODO: prevent pop */ /* TODO: prevent pop */
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
/* TODO */ /* TODO */
void pcm_rec_dma_init(void) void pcm_rec_dma_init(void)

View file

@ -26,13 +26,14 @@
#include "sound.h" #include "sound.h"
#include "pcm.h" #include "pcm.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
#include "cpu.h" #include "cpu.h"
/**************************************************************************** /****************************************************************************
** Playback DMA transfer ** Playback DMA transfer
**/ **/
void pcm_play_dma_postinit(void) static void sink_dma_postinit(void)
{ {
audiohw_postinit(); audiohw_postinit();
@ -40,7 +41,7 @@ void pcm_play_dma_postinit(void)
__aic_flush_tfifo(); __aic_flush_tfifo();
} }
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL)); system_enable_irq(DMA_IRQ(DMA_AIC_TX_CHANNEL));
@ -48,9 +49,9 @@ void pcm_play_dma_init(void)
audiohw_init(); audiohw_init();
} }
void pcm_dma_apply_settings(void) static void sink_set_freq(uint16_t freq)
{ {
audiohw_set_frequency(pcm_fsel); audiohw_set_frequency(freq);
} }
static const void* playback_address; static const void* playback_address;
@ -126,20 +127,7 @@ void DMA_CALLBACK(DMA_AIC_TX_CHANNEL)(void)
} }
} }
void pcm_play_dma_start(const void *addr, size_t size) static void sink_dma_stop(void)
{
pcm_play_dma_stop();
__dmac_channel_enable_clk(DMA_AIC_TX_CHANNEL);
set_dma(addr, size);
__aic_enable_replay();
__dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL);
}
void pcm_play_dma_stop(void)
{ {
int flags = disable_irq_save(); int flags = disable_irq_save();
@ -152,8 +140,21 @@ void pcm_play_dma_stop(void)
restore_irq(flags); restore_irq(flags);
} }
static void sink_dma_start(const void *addr, size_t size)
{
sink_dma_stop();
__dmac_channel_enable_clk(DMA_AIC_TX_CHANNEL);
set_dma(addr, size);
__aic_enable_replay();
__dmac_channel_enable_irq(DMA_AIC_TX_CHANNEL);
}
static unsigned int play_lock = 0; static unsigned int play_lock = 0;
void pcm_play_lock(void) static void sink_lock(void)
{ {
int flags = disable_irq_save(); int flags = disable_irq_save();
@ -163,7 +164,7 @@ void pcm_play_lock(void)
restore_irq(flags); restore_irq(flags);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
int flags = disable_irq_save(); int flags = disable_irq_save();
@ -172,3 +173,20 @@ void pcm_play_unlock(void)
restore_irq(flags); restore_irq(flags);
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = sink_dma_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};

View file

@ -25,6 +25,7 @@
#include "audiohw.h" #include "audiohw.h"
#include "pcm.h" #include "pcm.h"
#include "pcm-internal.h" #include "pcm-internal.h"
#include "pcm_sink.h"
#include "panic.h" #include "panic.h"
#include "dma-x1000.h" #include "dma-x1000.h"
#include "irq-x1000.h" #include "irq-x1000.h"
@ -53,7 +54,7 @@ static dma_desc rec_dma_desc;
static void pcm_rec_dma_int_cb(int event); static void pcm_rec_dma_int_cb(int event);
#endif #endif
void pcm_play_dma_init(void) static void sink_dma_init(void)
{ {
/* Ungate clock */ /* Ungate clock */
jz_writef(CPM_CLKGR, AIC(0)); jz_writef(CPM_CLKGR, AIC(0));
@ -99,14 +100,9 @@ void pcm_play_dma_init(void)
system_enable_irq(IRQ_AIC); system_enable_irq(IRQ_AIC);
} }
void pcm_play_dma_postinit(void) static void sink_set_freq(uint16_t freq)
{ {
audiohw_postinit(); audiohw_set_frequency(freq);
}
void pcm_dma_apply_settings(void)
{
audiohw_set_frequency(pcm_fsel);
} }
static void play_dma_start(const void* addr, size_t size) static void play_dma_start(const void* addr, size_t size)
@ -157,7 +153,7 @@ static void pcm_play_dma_int_cb(int event)
} }
} }
void pcm_play_dma_start(const void* addr, size_t size) static void sink_dma_start(const void* addr, size_t size)
{ {
play_dma_pending_event = DMA_EVENT_NONE; play_dma_pending_event = DMA_EVENT_NONE;
aic_state |= AIC_STATE_PLAYING; aic_state |= AIC_STATE_PLAYING;
@ -166,7 +162,7 @@ void pcm_play_dma_start(const void* addr, size_t size)
jz_writef(AIC_CCR, TDMS(1), ETUR(1), ERPL(1)); jz_writef(AIC_CCR, TDMS(1), ETUR(1), ERPL(1));
} }
void pcm_play_dma_stop(void) static void sink_dma_stop(void)
{ {
/* disable DMA and underrun interrupts */ /* disable DMA and underrun interrupts */
jz_writef(AIC_CCR, TDMS(0), ETUR(0)); jz_writef(AIC_CCR, TDMS(0), ETUR(0));
@ -180,7 +176,7 @@ void pcm_play_dma_stop(void)
if (jz_readf(AIC_I2SCR, STPBK) == 0) { if (jz_readf(AIC_I2SCR, STPBK) == 0) {
while(jz_readf(AIC_SR, TFL) != 0); while(jz_readf(AIC_SR, TFL) != 0);
} else { } else {
panicf("pcm_play_dma_stop: No bit clock running!"); panicf("sink_dma_stop: No bit clock running!");
} }
/* disable playback */ /* disable playback */
@ -190,14 +186,14 @@ void pcm_play_dma_stop(void)
aic_state &= ~AIC_STATE_PLAYING; aic_state &= ~AIC_STATE_PLAYING;
} }
void pcm_play_lock(void) static void sink_lock(void)
{ {
int irq = disable_irq_save(); int irq = disable_irq_save();
++play_lock; ++play_lock;
restore_irq(irq); restore_irq(irq);
} }
void pcm_play_unlock(void) static void sink_unlock(void)
{ {
int irq = disable_irq_save(); int irq = disable_irq_save();
if(--play_lock == 0 && (aic_state & AIC_STATE_PLAYING)) { if(--play_lock == 0 && (aic_state & AIC_STATE_PLAYING)) {
@ -208,6 +204,23 @@ void pcm_play_unlock(void)
restore_irq(irq); restore_irq(irq);
} }
struct pcm_sink builtin_pcm_sink = {
.caps = {
.samprs = hw_freq_sampr,
.num_samprs = HW_NUM_FREQ,
.default_freq = HW_FREQ_DEFAULT,
},
.ops = {
.init = sink_dma_init,
.postinit = audiohw_postinit,
.set_freq = sink_set_freq,
.lock = sink_lock,
.unlock = sink_unlock,
.play = sink_dma_start,
.stop = sink_dma_stop,
},
};
#ifdef HAVE_RECORDING #ifdef HAVE_RECORDING
/* /*
* Recording * Recording

View file

@ -194,6 +194,9 @@ each option pertains both to files and directories):
\item [Recording Directory.] \item [Recording Directory.]
Save recordings in the selected directory. Save recordings in the selected directory.
} }
\item [Always remember last folder.]
Saves the last position in the file browser on shutdown.
This directory (and if applicable last file) will be restored next boot.
\item [Start Directory.] \item [Start Directory.]
Set as default start directory for the File Browser. Set as default start directory for the File Browser.
\note{If you have \setting{Auto-Change Directory} and \note{If you have \setting{Auto-Change Directory} and

View file

@ -397,7 +397,7 @@ foreach my $id (@langorder) {
if ($id eq 'LANG_VOICED_DATE_FORMAT') { if ($id eq 'LANG_VOICED_DATE_FORMAT') {
my $sane = $lp{$tgt}; my $sane = $lp{$tgt};
$sane =~ s/^~?(.*)/$1/; # Strip off leading ~ if it's there as it's not a legal character for the format. $sane =~ s/^~?(.*)/$1/; # Strip off leading ~ if it's there as it's not a legal character for the format.
$sane =~ tr/YAmd~//d; $sane =~ tr/yYAmd~//d;
if (length($sane) != 0) { if (length($sane) != 0) {
$lang{$id}{'notes'} .= "### The <dest> section for '$id:$tgt' has illegal characters! Restoring from English!\n"; $lang{$id}{'notes'} .= "### The <dest> section for '$id:$tgt' has illegal characters! Restoring from English!\n";
$lang{$id}{'notes'} .= "#### the previously used one is commented below:\n"; $lang{$id}{'notes'} .= "#### the previously used one is commented below:\n";