A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

Link librockbox in Zig build and add bindings

Add Zig wrappers and C APIs for metadata, playlist, settings, tree
Update build to include library sources and link required static libs

+870 -35
+5 -2
apps/apps.make
··· 9 9 10 10 INCLUDES += -I$(APPSDIR) $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA))) 11 11 SRC += $(call preprocess, $(APPSDIR)/SOURCES) 12 + LIB_SRC += $(call preprocess, $(APPSDIR)/SOURCES) 13 + LIB_SRC += $(BUILDDIR)/lang/lang_core.c 14 + LIB_SRC += $(BUILDDIR)/apps/bitmaps/mono/*.c 15 + LIB_SRC += $(BUILDDIR)/apps/bitmaps/native/*.c 12 16 13 17 # apps/features.txt is a file that (is preprocessed and) lists named features 14 18 # based on defines in the config-*.h files. The named features will be passed ··· 39 43 40 44 ROCKBOXLIB = $(BUILDDIR)/librockbox.a 41 45 42 - ROCKBOXLIB_OBJ := $(call c2obj, $(SRC)) 46 + ROCKBOXLIB_OBJ := $(call c2obj, $(LIB_SRC)) 43 47 44 48 $(ROCKBOXLIB): $(ROCKBOXLIB_OBJ) 45 49 $(SILENT)$(shell rm -f $@) 46 50 $(call PRINTS,AR $(@F))$(AR) rcs $@ $^ >/dev/null 47 -
+1 -1
tools/root.make
··· 191 191 OBJ := $(call full_path_subst,$(ROOTDIR)/%,$(BUILDDIR)/%,$(OBJ)) 192 192 193 193 build: $(TOOLS) $(BUILDDIR)/$(BINARY) $(CODECS) $(ROCKS) $(RBINFO) 194 - lib: $(DEPFILE) $(ROCKBOXLIB) $(TOOLS) $(CODECS) $(ROCKS) 194 + lib: $(DEPFILE) $(ROCKBOXLIB) $(FIRMLIB) $(RBCODECLIB) $(CORE_LIBS) $(VOICESPEEXLIB) $(TOOLS) $(CODECS) $(ROCKS) 195 195 196 196 $(RBINFO): $(BUILDDIR)/$(BINARY) 197 197 $(SILENT)echo Creating $(@F)
+30 -13
zig/build.zig
··· 83 83 }), 84 84 }); 85 85 86 + exe.addLibraryPath(.{ 87 + .cwd_relative = "../target/release", 88 + }); 89 + 90 + if (target.result.os.tag == .macos) { 91 + exe.addLibraryPath(.{ .cwd_relative = "/opt/homebrew/lib" }); 92 + exe.linkFramework("CoreFoundation"); 93 + } 94 + 95 + const librockbox = b.path("../build-lib/librockbox.a"); 96 + const libfirmware = b.path("../build-lib/firmware/libfirmware.a"); 97 + const libfixedpoint = b.path("../build-lib/lib/libfixedpoint.a"); 98 + const librbcodec = b.path("../build-lib/lib/librbcodec.a"); 99 + const libskin_parser = b.path("../build-lib/lib/libskin_parser.a"); 100 + const libtlsf = b.path("../build-lib/lib/libtlsf.a"); 101 + const libspeex_voice = b.path("../build-lib/lib/rbcodec/codecs/libspeex-voice.a"); 102 + const librockbox_cli = b.path("../target/release/librockbox_cli.a"); 103 + const librockbox_server = b.path("../target/release/librockbox_server.a"); 104 + exe.addObjectFile(librockbox); 105 + exe.addObjectFile(libfirmware); 106 + exe.addObjectFile(libfixedpoint); 107 + exe.addObjectFile(libskin_parser); 108 + exe.addObjectFile(librbcodec); 109 + exe.addObjectFile(libtlsf); 110 + exe.addObjectFile(libspeex_voice); 111 + exe.addObjectFile(librockbox_cli); 112 + exe.addObjectFile(librockbox_server); 113 + exe.linkSystemLibrary("SDL2"); 114 + exe.linkLibC(); 115 + 86 116 // This declares intent for the executable to be installed into the 87 117 // install prefix when running `zig build` (i.e. when executing the default 88 118 // step). By default the install prefix is `zig-out/` but can be overridden ··· 141 171 const test_step = b.step("test", "Run tests"); 142 172 test_step.dependOn(&run_mod_tests.step); 143 173 test_step.dependOn(&run_exe_tests.step); 144 - 145 - exe.addLibraryPath(.{ 146 - .cwd_relative = "../target/release", 147 - }); 148 - 149 - const librockbox = b.path("../build-lib/librockbox.a"); 150 - exe.addObjectFile(librockbox); 151 - 152 - //exe.linkSystemLibrary("rockbox_cli"); 153 - //exe.linkSystemLibrary("rockbox_server"); 154 - //exe.linkSystemLibrary("unwind"); 155 - exe.linkSystemLibrary("SDL2"); 156 - exe.linkLibC(); 157 174 158 175 // Just like flags, top level steps are also listed in the `--help` menu. 159 176 //
+101 -19
zig/src/main.zig
··· 1 1 const std = @import("std"); 2 - const rockboxd = @import("rockboxd"); 2 + const playlist = @import("rockbox/playlist.zig"); 3 + const metadata = @import("rockbox/metadata.zig"); 4 + const tree = @import("rockbox/tree.zig"); 5 + const settings = @import("rockbox/settings.zig"); 6 + 7 + extern fn main_c() c_int; 8 + extern fn parse_args(argc: usize, argv: [*]const [*]const u8) c_int; 3 9 4 10 pub fn main() !void { 5 - // Prints to stderr, ignoring potential errors. 6 - std.debug.print("All your {s} are belong to us.\n", .{"codebase"}); 7 - try rockboxd.bufferedPrint(); 11 + const args = try std.process.argsAlloc(std.heap.page_allocator); 12 + defer std.process.argsFree(std.heap.page_allocator, args); 13 + 14 + var argv: [10][*]const u8 = undefined; 15 + 16 + var argc: usize = 0; 17 + 18 + if (args.len > 10) { 19 + std.debug.print("Too many arguments, max 10", .{}); 20 + std.process.exit(1); 21 + } 22 + 23 + for (args) |arg| { 24 + argv[argc] = @ptrCast(arg.ptr); 25 + argc += 1; 26 + } 27 + 28 + _ = parse_args(argc, &argv); 29 + _ = main_c(); 8 30 } 9 31 10 - test "simple test" { 11 - const gpa = std.testing.allocator; 12 - var list: std.ArrayList(i32) = .empty; 13 - defer list.deinit(gpa); // Try commenting this out and see if zig detects the memory leak! 14 - try list.append(gpa, 42); 15 - try std.testing.expectEqual(@as(i32, 42), list.pop()); 32 + // metadata functions 33 + export fn rb_get_metadata(fd: c_int, trackname: [*]const u8) metadata.mp3entry { 34 + return metadata._get_metadata(fd, trackname); 16 35 } 17 36 18 - test "fuzz example" { 19 - const Context = struct { 20 - fn testOne(context: @This(), input: []const u8) anyerror!void { 21 - _ = context; 22 - // Try passing `--fuzz` to `zig build test` and see if it manages to fail this test case! 23 - try std.testing.expect(!std.mem.eql(u8, "canyoufindme", input)); 24 - } 25 - }; 26 - try std.testing.fuzz(Context{}, Context.testOne, .{}); 37 + // browsing functions 38 + export fn rb_rockbox_browse() c_int { 39 + return tree._rockbox_browse(); 40 + } 41 + 42 + export fn rb_tree_get_context() tree.tree_context { 43 + return tree._tree_get_context(); 44 + } 45 + 46 + export fn rb_tree_get_entries() *tree.entry { 47 + return tree._tree_get_entries(); 48 + } 49 + 50 + export fn rb_tree_get_entry_at(index: c_int) tree.entry { 51 + return tree._tree_get_entry_at(index); 52 + } 53 + 54 + // playlist functions 55 + export fn rb_get_track_info_from_current_playlist(index: c_int) playlist.PlaylistTrackInfo { 56 + return playlist._get_track_info_from_current_playlist(index); 57 + } 58 + 59 + export fn rb_build_playlist(files: [*]const [*]const u8, start_index: c_int, size: c_int) c_int { 60 + return playlist.build_playlist(files, start_index, size); 61 + } 62 + 63 + export fn rb_playlist_insert_tracks(files: [*]const [*]const u8, position: c_int, size: c_int) c_int { 64 + return playlist.insert_tracks(files, position, size); 65 + } 66 + 67 + export fn rb_playlist_insert_track(filename: [*]const u8, position: c_int, queue: bool, sync: bool) c_int { 68 + return playlist.insert_track(filename, position, queue, sync); 69 + } 70 + 71 + export fn rb_playlist_delete_track(index: c_int) c_int { 72 + return playlist.delete_track(index); 73 + } 74 + 75 + export fn rb_playlist_insert_directory(dir: [*]const u8, position: c_int, queue: bool, recurse: bool) c_int { 76 + return playlist.insert_directory(dir, position, queue, recurse); 77 + } 78 + 79 + export fn rb_playlist_remove_all_tracks() c_int { 80 + return playlist.remove_all_tracks(); 81 + } 82 + 83 + export fn rb_playlist_index() c_int { 84 + return playlist.playlist_index(); 85 + } 86 + 87 + export fn rb_playlist_first_index() c_int { 88 + return playlist.playlist_first_index(); 89 + } 90 + 91 + export fn rb_playlist_last_insert_pos() c_int { 92 + return playlist.playlist_last_insert_pos(); 93 + } 94 + 95 + export fn rb_playlist_seed() c_int { 96 + return playlist.playlist_seed(); 97 + } 98 + 99 + export fn rb_playlist_last_shuffled_start() c_int { 100 + return playlist.playlist_last_shuffled_start(); 101 + } 102 + 103 + export fn rb_max_playlist_size() c_int { 104 + return playlist.max_playlist_size(); 105 + } 106 + 107 + export fn rb_get_crossfade_mode() c_int { 108 + return settings.get_crossfade_mode(); 27 109 }
+85
zig/src/rockbox/metadata.zig
··· 1 + pub const MAX_PATH = 260; 2 + pub const ID3V2_BUF_SIZE = 1800; 3 + 4 + const mp3_aa_type = enum(c_int) { 5 + AA_TYPE_UNSYNC = -1, 6 + AA_TYPE_UNKNOWN = 0, 7 + AA_TYPE_BMP, 8 + AA_TYPE_PNG, 9 + AA_TYPE_JPG, 10 + }; 11 + 12 + const mp3_albumart = extern struct { 13 + type: mp3_aa_type, 14 + size: c_int, 15 + pos: c_long, // Use c_long to match the typical size of off_t, but adjust as necessary 16 + }; 17 + 18 + pub const mp3entry = extern struct { 19 + path: [MAX_PATH]u8, 20 + title: ?*[*c]u8, 21 + artist: ?*[*c]u8, 22 + album: ?*[*c]u8, 23 + genre_string: ?*[*c]u8, 24 + disc_string: ?*[*c]u8, 25 + track_string: ?*[*c]u8, 26 + year_string: ?*[*c]u8, 27 + composer: ?*[*c]u8, 28 + comment: ?*[*c]u8, 29 + albumartist: ?*[*c]u8, 30 + grouping: ?*[*c]u8, 31 + discnum: c_int, 32 + tracknum: c_int, 33 + layer: c_int, 34 + year: c_int, 35 + id3version: u8, 36 + codectype: u32, 37 + bitrate: u32, 38 + frequency: u32, 39 + id3v2len: u32, 40 + id3v1len: u32, 41 + first_frame_offset: u32, 42 + filesize: u32, 43 + length: u32, 44 + elapsed: u32, 45 + lead_trim: c_int, 46 + tail_trim: c_int, 47 + samples: u64, 48 + frame_count: u32, 49 + bytesperframe: u32, 50 + vbr: bool, 51 + has_toc: bool, 52 + toc: [100]u8, 53 + needs_upsampling_correction: bool, 54 + id3v2buf: [ID3V2_BUF_SIZE]u8, 55 + id3v1buf: [4][92]u8, 56 + offset: u32, 57 + index: c_int, 58 + skip_resume_adjustments: bool, 59 + autoresumable: u8, 60 + tagcache_idx: c_long, 61 + rating: c_int, 62 + score: c_int, 63 + playcount: c_long, 64 + lastplayed: c_long, 65 + playtime: c_long, 66 + track_level: c_long, 67 + album_level: c_long, 68 + track_gain: c_long, 69 + album_gain: c_long, 70 + track_peak: c_long, 71 + album_peak: c_long, 72 + has_embedded_albumart: bool, 73 + albumart: mp3_albumart, 74 + has_embedded_cuesheet: bool, 75 + mb_track_id: ?*[*c]u8, 76 + is_asf_stream: bool, 77 + }; 78 + 79 + extern fn get_metadata(id3: *mp3entry, fd: c_int, trackname: [*]const u8) bool; 80 + 81 + pub fn _get_metadata(fd: c_int, trackname: [*]const u8) mp3entry { 82 + var id3: mp3entry = undefined; 83 + _ = get_metadata(&id3, fd, trackname); 84 + return id3; 85 + }
+160
zig/src/rockbox/playlist.zig
··· 1 + const MAX_PATH = 260; 2 + const PLAYLIST_CONTROL_FILE_SIZE = 256; 3 + 4 + const PLAYLIST_PREPEND = -1; 5 + const PLAYLIST_INSERT = -2; 6 + const PLAYLIST_INSERT_LAST = -3; 7 + const PLAYLIST_INSERT_FIRST = -4; 8 + const PLAYLIST_INSERT_SHUFFLED = -5; 9 + const PLAYLIST_REPLACE = -6; 10 + const PLAYLIST_INSERT_LAST_SHUFFLED = -7; 11 + const PLAYLIST_INSERT_LAST_ROTATED = -8; 12 + 13 + pub const PlaylistInfo = extern struct { 14 + utf8: bool, 15 + control_created: bool, 16 + flags: c_uint, 17 + fd: c_int, 18 + control_fd: c_int, 19 + max_playlist_size: c_int, 20 + indices: ?*c_ulong, 21 + index: c_int, 22 + first_index: c_int, 23 + amount: c_int, 24 + last_insert_pos: c_int, 25 + started: bool, 26 + last_shuffled_start: c_int, 27 + seed: c_int, 28 + dcfrefs_handle: c_int, 29 + dirlen: c_int, 30 + filename: [MAX_PATH]u8, 31 + control_filename: [PLAYLIST_CONTROL_FILE_SIZE + 8]u8, 32 + }; 33 + 34 + pub const PlaylistTrackInfo = extern struct { 35 + filename: [260]u8, 36 + attr: c_int, 37 + index: c_int, 38 + display_index: c_int, 39 + }; 40 + 41 + pub const PlaylistInsertContext = extern struct { 42 + playlist: *PlaylistInfo, 43 + position: c_int, 44 + queue: bool, 45 + progress: bool, 46 + initialized: bool, 47 + count: c_int, 48 + count_langid: c_int, 49 + }; 50 + 51 + extern fn playlist_get_current() *PlaylistInfo; 52 + extern fn playlist_get_track_info(playlist: *PlaylistInfo, index: c_int, info: *PlaylistTrackInfo) c_int; 53 + extern fn playlist_create(dir: [*]const u8, file: [*]const u8) c_int; 54 + extern fn playlist_insert_context_create(playlist: *PlaylistInfo, context: *PlaylistInsertContext, position: c_int, queue: bool, progress: bool) c_int; 55 + extern fn playlist_insert_context_release(context: *PlaylistInsertContext) void; 56 + extern fn playlist_insert_context_add(context: *PlaylistInsertContext, filename: [*]const u8) c_int; 57 + extern fn playlist_delete(playlist: *PlaylistInfo, index: c_int) c_int; 58 + extern fn playlist_insert_track(playlist: *PlaylistInfo, filename: [*]const u8, position: c_int, queue: bool, sync: bool) c_int; 59 + extern fn playlist_insert_directory(playlist: *PlaylistInfo, dir: [*]const u8, position: c_int, queue: bool, recurse: bool) c_int; 60 + extern fn playlist_remove_all_tracks(playlist: *PlaylistInfo) c_int; 61 + 62 + pub fn _get_track_info_from_current_playlist(index: c_int) PlaylistTrackInfo { 63 + const playlist = playlist_get_current(); 64 + var info: PlaylistTrackInfo = undefined; 65 + _ = playlist_get_track_info(playlist, index, &info); 66 + return info; 67 + } 68 + 69 + pub fn build_playlist(files: [*]const [*]const u8, start_index: c_int, size: c_int) c_int { 70 + const start = start_index; 71 + const playlist = playlist_get_current(); 72 + var context: PlaylistInsertContext = undefined; 73 + 74 + if (playlist_insert_context_create(playlist, &context, PLAYLIST_REPLACE, false, false) < 0) { 75 + return -1; 76 + } 77 + 78 + var i: usize = 0; 79 + while (i < size) { 80 + const res = playlist_insert_context_add(&context, files[i]); 81 + if (res < 0) { 82 + break; 83 + } 84 + i += 1; 85 + } 86 + 87 + playlist_insert_context_release(&context); 88 + return start; 89 + } 90 + 91 + pub fn insert_tracks(files: [*]const [*]const u8, position: c_int, size: c_int) c_int { 92 + const playlist = playlist_get_current(); 93 + var context: PlaylistInsertContext = undefined; 94 + 95 + if (playlist_insert_context_create(playlist, &context, position, false, false) < 0) { 96 + return -1; 97 + } 98 + 99 + var i: usize = 0; 100 + while (i < size) { 101 + const res = playlist_insert_context_add(&context, files[i]); 102 + if (res < 0) { 103 + break; 104 + } 105 + i += 1; 106 + } 107 + 108 + playlist_insert_context_release(&context); 109 + return position; 110 + } 111 + 112 + pub fn insert_track(filename: [*]const u8, position: c_int, queue: bool, sync: bool) c_int { 113 + const playlist = playlist_get_current(); 114 + return playlist_insert_track(playlist, filename, position, queue, sync); 115 + } 116 + 117 + pub fn delete_track(index: c_int) c_int { 118 + const playlist = playlist_get_current(); 119 + return playlist_delete(playlist, index); 120 + } 121 + 122 + pub fn insert_directory(dir: [*]const u8, position: c_int, queue: bool, recurse: bool) c_int { 123 + const playlist = playlist_get_current(); 124 + return playlist_insert_directory(playlist, dir, position, queue, recurse); 125 + } 126 + 127 + pub fn remove_all_tracks() c_int { 128 + const playlist = playlist_get_current(); 129 + return playlist_remove_all_tracks(playlist); 130 + } 131 + 132 + pub fn playlist_index() c_int { 133 + const playlist = playlist_get_current(); 134 + return playlist.index; 135 + } 136 + 137 + pub fn playlist_first_index() c_int { 138 + const playlist = playlist_get_current(); 139 + return playlist.first_index; 140 + } 141 + 142 + pub fn playlist_last_insert_pos() c_int { 143 + const playlist = playlist_get_current(); 144 + return playlist.last_insert_pos; 145 + } 146 + 147 + pub fn playlist_seed() c_int { 148 + const playlist = playlist_get_current(); 149 + return playlist.seed; 150 + } 151 + 152 + pub fn playlist_last_shuffled_start() c_int { 153 + const playlist = playlist_get_current(); 154 + return playlist.last_shuffled_start; 155 + } 156 + 157 + pub fn max_playlist_size() c_int { 158 + const playlist = playlist_get_current(); 159 + return playlist.max_playlist_size; 160 + }
+361
zig/src/rockbox/settings.zig
··· 1 + pub const std = @import("std"); 2 + 3 + pub const EQ_NUM_BANDS = 10; 4 + pub const QUICKSCREEN_ITEM_COUNT = 4; 5 + pub const MAX_FILENAME = 32; 6 + pub const MAX_PATHNAME = 256; 7 + 8 + pub const ReplaygainSettings = extern struct { 9 + noclip: bool, 10 + type: c_int, 11 + preamp: c_int, 12 + }; 13 + 14 + pub const EqBandSetting = extern struct { 15 + cutoff: c_int, 16 + gain: c_int, 17 + q: c_int, 18 + }; 19 + 20 + pub const StorageType = extern union { int_val: c_int }; 21 + 22 + pub const SoundSetting = extern struct { setting: c_int }; 23 + 24 + pub const BoolSetting = extern struct { lang_yes: c_int, lang_no: c_int }; 25 + 26 + pub const FilenameSetting = extern struct { 27 + prefix: [*]const u8, 28 + suffix: [*]const u8, 29 + max_len: c_int, 30 + }; 31 + 32 + pub const IntSetting = extern struct { 33 + unit: c_int, 34 + step: c_int, 35 + min: c_int, 36 + max: c_int, 37 + }; 38 + 39 + pub const ChoiceSettingData = extern struct { 40 + desc: [*]const [*]const u8, 41 + talks: [*]const c_int, 42 + }; 43 + 44 + pub const ChoiceSetting = extern struct { 45 + count: c_int, 46 + data: ChoiceSettingData, 47 + }; 48 + 49 + pub const TableSetting = extern struct { 50 + unit: c_int, 51 + count: c_int, 52 + values: [*]const c_int, 53 + }; 54 + 55 + pub const CustomSetting = extern struct { 56 + unit: c_int, 57 + count: c_int, 58 + values: [*]const c_int, 59 + }; 60 + 61 + pub const SettingsTypeUnion = extern union { 62 + sound_setting: SoundSetting, 63 + bool_setting: BoolSetting, 64 + filename_setting: FilenameSetting, 65 + int_setting: IntSetting, 66 + choice_setting: ChoiceSetting, 67 + table_setting: TableSetting, 68 + custom_setting: CustomSetting, 69 + }; 70 + 71 + pub const SettingsList = extern struct { 72 + flags: c_uint, 73 + lang_id: c_int, 74 + default_val: StorageType, 75 + cfg_name: [*]const u8, 76 + cfg_vals: [*]const u8, 77 + settings_type: SettingsTypeUnion, 78 + }; 79 + 80 + pub const TouchscreenParameter = extern struct { 81 + A: c_int, 82 + B: c_int, 83 + C: c_int, 84 + D: c_int, 85 + E: c_int, 86 + F: c_int, 87 + divider: c_int, 88 + }; 89 + 90 + pub const CompressorSettings = extern struct { 91 + threshold: c_int, 92 + makeup_gain: c_int, 93 + ratio: c_int, 94 + knee: c_int, 95 + release_time: c_int, 96 + attack_time: c_int, 97 + }; 98 + 99 + pub const UserSettings = extern struct { 100 + // Audio settings 101 + volume: c_int, 102 + balance: c_int, 103 + bass: c_int, 104 + treble: c_int, 105 + channel_config: c_int, 106 + stereo_width: c_int, 107 + 108 + bass_cutoff: c_int, 109 + treble_cutoff: c_int, 110 + 111 + crossfade: c_int, 112 + crossfade_fade_in_delay: c_int, 113 + crossfade_fade_out_delay: c_int, 114 + crossfade_fade_in_duration: c_int, 115 + crossfade_fade_out_duration: c_int, 116 + crossfade_fade_out_mixmode: c_int, 117 + 118 + // Replaygain 119 + replaygain_settings: ReplaygainSettings, 120 + 121 + // Crossfeed 122 + crossfeed: c_int, 123 + crossfeed_direct_gain: c_uint, 124 + crossfeed_cross_gain: c_uint, 125 + crossfeed_hf_attenuation: c_uint, 126 + crossfeed_hf_cutoff: c_uint, 127 + 128 + // EQ 129 + eq_enabled: u8, 130 + eq_precut: c_uint, 131 + eq_band_settings: [EQ_NUM_BANDS]EqBandSetting, 132 + 133 + // Misc. swcodec 134 + beep: c_int, 135 + keyclick: c_int, 136 + keyclick_repeats: c_int, 137 + dithering_enabled: u8, 138 + timestretch_enabled: u8, 139 + 140 + // Misc options 141 + list_accel_start_delay: c_int, 142 + list_accel_wait: c_int, 143 + 144 + touchpad_sensitivity: c_int, 145 + touchpad_deadzone: c_int, 146 + 147 + pause_rewind: c_int, 148 + unplug_mode: c_int, 149 + unplug_autoresume: u8, 150 + 151 + qs_items: [QUICKSCREEN_ITEM_COUNT]SettingsList, 152 + 153 + timeformat: c_int, 154 + disk_spindown: c_int, 155 + buffer_margin: c_int, 156 + 157 + dirfilter: c_int, 158 + show_filename_ext: c_int, 159 + default_codepage: c_int, 160 + hold_lr_for_scroll_in_list: u8, 161 + play_selected: u8, 162 + single_mode: c_int, 163 + party_mode: u8, 164 + cuesheet: u8, 165 + car_adapter_mode: u8, 166 + car_adapter_mode_delay: c_int, 167 + start_in_screen: c_int, 168 + ff_rewind_min_step: c_int, 169 + ff_rewind_accel: c_int, 170 + 171 + peak_meter_release: c_int, 172 + peak_meter_hold: c_int, 173 + peak_meter_clip_hold: c_int, 174 + peak_meter_dbfs: u8, 175 + peak_meter_min: c_int, 176 + peak_meter_max: c_int, 177 + 178 + wps_file: [MAX_FILENAME + 1]u8, 179 + sbs_file: [MAX_FILENAME + 1]u8, 180 + lang_file: [MAX_FILENAME + 1]u8, 181 + playlist_catalog_dir: [MAX_PATHNAME + 1]u8, 182 + skip_length: c_int, 183 + max_files_in_dir: c_int, 184 + max_files_in_playlist: c_int, 185 + volume_type: c_int, 186 + battery_display: c_int, 187 + show_icons: u8, 188 + statusbar: c_int, 189 + 190 + scrollbar: c_int, 191 + scrollbar_width: c_int, 192 + 193 + list_line_padding: c_int, 194 + list_separator_height: c_int, 195 + list_separator_color: c_int, 196 + 197 + browse_current: u8, 198 + scroll_paginated: u8, 199 + list_wraparound: u8, 200 + list_order: c_int, 201 + scroll_speed: c_int, 202 + bidir_limit: c_int, 203 + scroll_delay: c_int, 204 + scroll_step: c_int, 205 + 206 + autoloadbookmark: c_int, 207 + autocreatebookmark: c_int, 208 + autoupdatebookmark: u8, 209 + usemrb: c_int, 210 + 211 + dircache: u8, 212 + tagcache_ram: c_int, 213 + tagcache_autoupdate: u8, 214 + autoresume_enable: u8, 215 + autoresume_automatic: c_int, 216 + autoresume_paths: [MAX_PATHNAME + 1]u8, 217 + runtimedb: u8, 218 + tagcache_scan_paths: [MAX_PATHNAME + 1]u8, 219 + tagcache_db_path: [MAX_PATHNAME + 1]u8, 220 + backdrop_file: [MAX_PATHNAME + 1]u8, 221 + 222 + bg_color: c_int, 223 + fg_color: c_int, 224 + lss_color: c_int, 225 + lse_color: c_int, 226 + lst_color: c_int, 227 + colors_file: [MAX_FILENAME + 1]u8, 228 + 229 + browser_default: c_int, 230 + 231 + repeat_mode: c_int, 232 + next_folder: c_int, 233 + constrain_next_folder: u8, 234 + recursive_dir_insert: c_int, 235 + fade_on_stop: u8, 236 + playlist_shuffle: u8, 237 + warnon_erase_dynplaylist: u8, 238 + keep_current_track_on_replace_playlist: u8, 239 + show_shuffled_adding_options: u8, 240 + show_queue_options: c_int, 241 + album_art: c_int, 242 + rewind_across_tracks: u8, 243 + 244 + playlist_viewer_icons: u8, 245 + playlist_viewer_indices: u8, 246 + playlist_viewer_track_display: c_int, 247 + 248 + talk_menu: u8, 249 + talk_dir: c_int, 250 + talk_dir_clip: u8, 251 + talk_file: c_int, 252 + talk_file_clip: u8, 253 + talk_filetype: u8, 254 + talk_battery_level: u8, 255 + talk_mixer_amp: c_int, 256 + 257 + sort_case: u8, 258 + sort_dir: c_int, 259 + sort_file: c_int, 260 + interpret_numbers: c_int, 261 + 262 + poweroff: c_int, 263 + battery_capacity: c_int, 264 + battery_type: c_int, 265 + spdif_enable: u8, 266 + usb_charging: c_int, 267 + 268 + contrast: c_int, 269 + invert: u8, 270 + flip_display: u8, 271 + cursor_style: c_int, 272 + screen_scroll_step: c_int, 273 + show_path_in_browser: c_int, 274 + offset_out_of_view: u8, 275 + disable_mainmenu_scrolling: u8, 276 + icon_file: [MAX_FILENAME + 1]u8, 277 + viewers_icon_file: [MAX_FILENAME + 1]u8, 278 + font_file: [MAX_FILENAME + 1]u8, 279 + glyphs_to_cache: c_int, 280 + kbd_file: [MAX_FILENAME + 1]u8, 281 + backlight_timeout: c_int, 282 + caption_backlight: u8, 283 + bl_filter_first_keypress: u8, 284 + backlight_timeout_plugged: c_int, 285 + bt_selective_softlock_actions: u8, 286 + bt_selective_softlock_actions_mask: c_int, 287 + bl_selective_actions: u8, 288 + bl_selective_actions_mask: c_int, 289 + backlight_on_button_hold: c_int, 290 + lcd_sleep_after_backlight_off: c_int, 291 + brightness: c_int, 292 + 293 + speaker_mode: c_int, 294 + prevent_skip: u8, 295 + 296 + touch_mode: c_int, 297 + ts_calibration_data: TouchscreenParameter, 298 + 299 + pitch_mode_semitone: u8, 300 + pitch_mode_timestretch: u8, 301 + 302 + usb_hid: u8, 303 + usb_keypad_mode: c_int, 304 + 305 + usb_skip_first_drive: u8, 306 + 307 + ui_vp_config: [64]u8, 308 + player_name: [64]u8, 309 + 310 + compressor_settings: CompressorSettings, 311 + 312 + sleeptimer_duration: c_int, 313 + sleeptimer_on_startup: u8, 314 + keypress_restarts_sleeptimer: u8, 315 + 316 + show_shutdown_message: u8, 317 + 318 + hotkey_wps: c_int, 319 + hotkey_tree: c_int, 320 + 321 + resume_rewind: c_int, 322 + 323 + depth_3d: c_int, 324 + 325 + roll_off: c_int, 326 + 327 + power_mode: c_int, 328 + 329 + keyclick_hardware: u8, 330 + 331 + start_directory: [MAX_PATHNAME + 1]u8, 332 + root_menu_customized: u8, 333 + shortcuts_replaces_qs: u8, 334 + 335 + play_frequency: c_int, 336 + volume_limit: c_int, 337 + 338 + volume_adjust_mode: c_int, 339 + volume_adjust_norm_steps: c_int, 340 + 341 + surround_enabled: c_int, 342 + surround_balance: c_int, 343 + surround_fx1: c_int, 344 + surround_fx2: u8, 345 + surround_method2: u8, 346 + surround_mix: c_int, 347 + 348 + pbe: c_int, 349 + pbe_precut: c_int, 350 + 351 + afr_enabled: c_int, 352 + 353 + governor: c_int, 354 + stereosw_mode: c_int, 355 + }; 356 + 357 + extern var global_settings: UserSettings; 358 + 359 + pub fn get_crossfade_mode() c_int { 360 + return global_settings.crossfade; 361 + }
+127
zig/src/rockbox/tree.zig
··· 1 + const std = @import("std"); 2 + 3 + pub const MAX_PATH = 260; 4 + pub const MAX_DIR_LEVELS = 10; 5 + 6 + const themable_icons = enum(c_int) { 7 + NOICON = -2, 8 + Icon_NOICON = -1, 9 + Icon_Audio, 10 + Icon_Folder, 11 + Icon_Playlist, 12 + Icon_Cursor, 13 + Icon_Wps, 14 + Icon_Firmware, 15 + Icon_Font, 16 + Icon_Language, 17 + Icon_Config, 18 + Icon_Plugin, 19 + Icon_Bookmark, 20 + Icon_Preset, 21 + Icon_Queued, 22 + Icon_Moving, 23 + Icon_Keyboard, 24 + Icon_Reverse_Cursor, 25 + Icon_Questionmark, 26 + Icon_Menu_setting, 27 + Icon_Menu_functioncall, 28 + Icon_Submenu, 29 + Icon_Submenu_Entered, 30 + Icon_Recording, 31 + Icon_Voice, 32 + Icon_General_settings_menu, 33 + Icon_System_menu, 34 + Icon_Playback_menu, 35 + Icon_Display_menu, 36 + Icon_Remote_Display_menu, 37 + Icon_Radio_screen, 38 + Icon_file_view_menu, 39 + Icon_EQ, 40 + Icon_Rockbox, 41 + Icon_Last_Themeable, 42 + }; 43 + 44 + pub const browse_context = extern struct { 45 + dirfilter: c_int, 46 + flags: c_uint, // 'unsigned' is translated to 'c_uint' 47 + title: [*c]const u8, // Nullable C string for the title 48 + icon: themable_icons, // Enum 'themable_icons', assumed to be defined elsewhere 49 + root: [*c]const u8, // Const C string for root directory path 50 + selected: [*c]const u8, // Const C string for selected file name 51 + buf: [*c]u8, // Buffer for the selected file 52 + bufsize: usize, // Size of the buffer (translated to 'usize' for portability) 53 + }; 54 + 55 + const tree_cache = extern struct { 56 + entries_handle: c_int, // Handle to the entry cache 57 + name_buffer_handle: c_int, // Handle to the name cache 58 + max_entries: c_int, // Maximum number of entries in the cache 59 + name_buffer_size: c_int, // Size of the name buffer (in bytes) 60 + }; 61 + 62 + pub const tree_context = extern struct { 63 + currdir: [MAX_PATH]u8, // Fixed-size array for the current directory 64 + dirlevel: i32, // int in C is c_int in Zig 65 + selected_item: i32, // Selected file/id3dbitem index 66 + selected_item_history: [MAX_DIR_LEVELS]c_int, // History of selected items, fixed-size array 67 + 68 + dirfilter: ?*c_int, // Nullable pointer to an int for file use 69 + filesindir: i32, // Number of files in the directory cache 70 + dirsindir: i32, // Directory use 71 + dirlength: i32, // Total number of entries in directory 72 + 73 + currtable: i32, 74 + currextra: i32, 75 + 76 + sort_dir: i32, // Directory sort order 77 + out_of_tree: i32, // Shortcut from elsewhere 78 + cache: tree_cache, // Struct tree_cache, defined elsewhere 79 + 80 + dirfull: bool, 81 + is_browsing: bool, 82 + 83 + browse: ?*browse_context, // Pointer to browse_context, nullable 84 + }; 85 + pub const entry = extern struct { 86 + name: ?*c_char, // Pointer to the name (nullable) 87 + attr: c_int, // FAT attributes + file type flags 88 + time_write: c_uint, // Last write time (unsigned) 89 + customaction: c_int, // Custom action (for database use) 90 + }; 91 + 92 + extern fn tree_init() void; 93 + extern fn rockbox_browse(browse: ?*browse_context) c_int; 94 + extern fn rockbox_browse_at(path: [*]const u8) c_int; 95 + extern fn tree_get_context() *tree_context; 96 + extern fn tree_get_entries(t: *tree_context) *entry; 97 + extern fn tree_get_entry_at(t: *tree_context, index: c_int) *entry; 98 + 99 + pub fn _rockbox_browse() c_int { 100 + var browse: browse_context = .{ 101 + .dirfilter = 0, 102 + .flags = 0, 103 + .title = "demo", 104 + .icon = themable_icons.Icon_NOICON, 105 + .root = "/", 106 + .selected = null, 107 + .buf = null, 108 + .bufsize = 0, 109 + }; 110 + return rockbox_browse(&browse); 111 + } 112 + 113 + pub fn _tree_get_context() tree_context { 114 + const tc = tree_get_context(); 115 + return tc.*; 116 + } 117 + 118 + pub fn _tree_get_entries() *entry { 119 + const tc = tree_get_context(); 120 + return tree_get_entries(tc); 121 + } 122 + 123 + pub fn _tree_get_entry_at(index: c_int) entry { 124 + const tc = tree_get_context(); 125 + const e = tree_get_entry_at(tc, index); 126 + return e.*; 127 + }