Skip to content

Conversation

@Logickin-Lambda
Copy link
Contributor

@Logickin-Lambda Logickin-Lambda commented Aug 30, 2025

As mentioned in this issues, I was working on the decoder type so that we can process audio at low level which is useful for custom decoders or more complicated audio applications due to the ability of access the output buffer directly with the function "readPCMFrames()" suggested by the official miniaudio documentation. My Resampler_Decoder_Prototype branch has a working prototype currently.

The current version is subjected to change because I have some questions related to the my current implementation and the callback function:

Since the current callback function from device use callconv(.c) void as return type which it doesn't support the zig error, but due to the current coding convention to handle the Result type:

pub fn functions(
    // input params...
) Error!void {
    try maybeError( extern_fn_from_miniaudio(...));
}

This makes decoder has to explicitly handle the error in the callback function like shown:

decoder.readPCMFrames(pOutput.?, frame_count, &frames_read) catch |err| {
    std.debug.print("ERROR: {any}", .{err});
    return;
};

I tried to change the return type of the callback function as !void, and trying to cast the function with pointer cast when I am creating the device like shown:

device_config.data_callback = @ptrCast(&data_callback);

Despite the lack of compile error, the device can't trigger the callback at run time. Should we keep the explicit error handling in the callback function, or a better ways to handle error inside such functions?

In addition, since testing the decoder requires sample files to begin with, besides a separate project for testing the function externally, what kind of tests can be included within the library?

Previously, I didn't carefully read the original
implementation and how zaudio bridges the function,
created a bunch of mess.

With a bit more studies, I think I have more confidence
on porting Decoder Type into zaudio, starting
with the unimplemented type for the Decoder so that
I don't get lost in the midway of creating the
Decoder type.
The coding part of DataConverter is now done, but
this will require testing; nonetheless, now we have
the DataConverter and Resampler.Config, building
the decoder should be less difficult.

I will test all the type once I have done decoder.
There is nothing interesting in this commit because
I am only half way through the Decoder type.
The bridge has been finished for Decoder, but since
the zaudio doesn't handle the wchar_t type from the
original C implementation, I am not going to port
any functions that involve the type unless there
are a better one size fits all solutions for all
other functions requiring wchar_t as well.
All of the coding related to the decoder is done,
but clearly, there will be many errors in the code
especially the pointer which I have missed out
a bunch of optionals.

Thus, I will do a series of testing to ensure
everything works fine, and after all, we will finally
able to load ourselves some samples at the low
level using zaudio.
The library is finally successfully compiled, but
clearly this is not enough because we need to test
if the library really works in practice; thus,
we are going to do some test to ensure the correct
of the decoders.
There are many more test to do, but I can't do this
on the zaudio level where there is no way to place
the callback function within the test block.

I will open up a separated project to conduct a
series of testing such that to ensure the functions
working flawlessly and acting as an example code
to overcome with the lacking low-level example
for zaudio.
This commit addresses the inconsistent convention
for channel_map input parameter for the decoder type,
and handle a case where some operation requiring
to passing the decoder as datasource for other functions.

The decoder is now confirmed to fetch and decoder
mp3 successfully in a separated project, but more
test are required to be conducted, not to mention
that the pull request will be done after zig 0.15.1
has properly been merged.
@Logickin-Lambda Logickin-Lambda changed the title [WIP and Disscusion] Decoder Type [WIP and Discussion] Decoder Type Aug 30, 2025
Logickin-Lambda and others added 4 commits September 1, 2025 16:54
The original function that involving channel_map
has an inconsistent input type comparing with other
existing function. In this version, I have replaced
the two parameters channel_map and channel_map_cap
with a slice for my decoder type.

All of the implemented functions for decoder are
tested and have worked properly; thus, the next
task will be testing about the data converter and
add the remaining function I missed from the previous
commits.
After the test, it turns out the config init Functions
are missing in the type, so I have added it such
that we can have a more convenient way to declare
the converter.
@Logickin-Lambda
Copy link
Contributor Author

Logickin-Lambda commented Sep 2, 2025

As mentioned previously, most of the decoder functions are not possible to be tested because they need audio files, and it doesn't looks like a good idea to include the testing audio file into the library, so I have written some demos to demonstrate how to use my newly ported Decoder and DataConverter type, along with some tests to ensure everything works fine:

https://github.com/Logickin-Lambda/zaudio_lib_upgrade_test

@hazeycode hazeycode requested a review from Copilot September 7, 2025 11:13
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces decoder and data converter types to zaudio, enabling low-level audio processing capabilities. The work adds comprehensive bindings for miniaudio's decoder and data converter functionality, allowing direct access to PCM frame data for custom audio processing applications.

Key changes:

  • Added Decoder type with methods for reading PCM frames, seeking, and format information
  • Added DataConverter type for audio format conversion and resampling
  • Added supporting enums DitherMode and EncodingFormat

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
src/zaudio.zig Adds Decoder and DataConverter opaque types with comprehensive method bindings
src/zaudio.c Implements C wrapper functions for decoder and data converter creation/destruction
README.md Updates feature list to include Decoder and DataConverter types

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@hazeycode
Copy link
Member

Re error handling in C callbacks, there's indeed no way to emit Zig errors and callback implementations should handle all possible errors internally. Logging out errors that occur in callbacks is certainly reasonable.

@Logickin-Lambda
Copy link
Contributor Author

Thanks, for that case, I will note that down into my example, and for the time being, let me have a look if I need to correct something based on the copilot review.

The GitHub review does reflect the inconsistency of
my code, with comparing the existing code from the
library.

Thus, I have made the change according to the
copilot review such that to align the coding
standard and format of the existing codebase.
@Logickin-Lambda
Copy link
Contributor Author

The suggestion from the Copilot is valid because after comparing the existing code, they are actually some coding and naming mistake. With the latest update, I have updated the code and comments such that the naming conventions and the format aligns to the existing code.

Copy link
Member

@hazeycode hazeycode left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! Nice work. Just some nitpicks about overly-verbose comments.

src/zaudio.zig Outdated
Comment on lines 466 to 470
// these functions were originally located under vfs, but they seems to have no correlation to the type,
// while decoder require such type in order to make it work, so I will temporary locate these functions in here:
pub const readProc = *const fn (user_data: ?*anyopaque, buffer_out: ?*anyopaque, bytes_to_read: usize, bytes_read: *usize) callconv(.c) Result;
pub const seekProc = *const fn (user_data: ?*anyopaque, offset: i64, origin: Vfs.SeekOrigin) callconv(.c) Result;
pub const tellProc = *const fn (user_data: ?*anyopaque, cursor: ?*i64) callconv(.c) Result;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, fine to move these. Let's delete the comments.

src/zaudio.zig Outdated
Comment on lines 933 to 934
// here are the init functions, but after observed other examples
// I will skip the _w variant until there is a solution to handle wchar_t
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comments not useful beyond code review. Please delete.

src/zaudio.zig Outdated
}
extern fn zaudioDecoderCreateFromFile(file_path: [*:0]const u8, config: *const Config, out_handle: ?*?*Decoder) Result;

// The remaing related functions for manipulate the samples:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unclear comment, please delete.

@hazeycode
Copy link
Member

Re tests: it would be nice to increase coverage but we can follow up after this PR.

@Logickin-Lambda
Copy link
Contributor Author

Thanks! I have removed those comments.

For the testing, I do have some ideas though:

Testing Data Converter should be simple since it only requires an anyopaque type of an array, so we could construct a [256]u8 array containing upward saw wave to these the conversion process.

However, testing the decoder without the audio file is a bit more complicated since I tried to feed a raw sample into the decoder but it didn't work because it only support either .wav, .flac, and mp3. The only plausible solution I know is to also port the encoder. With the encoder, we could do a test by encoding a raw sample array into .wav format, and decode it back with comparing the original raw sample array.

The two solutions above should eliminate the use of sample files so that we can fit the test within a single test block.

@hazeycode hazeycode merged commit 2abe66f into zig-gamedev:main Sep 14, 2025
3 checks passed
@hazeycode hazeycode changed the title [WIP and Discussion] Decoder Type Add ma_decoder bindings Sep 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants