mackron / miniaudio

Audio playback and capture library written in C, in a single source file.
https://miniaud.io
Other
4.07k stars 361 forks source link

simple_capture with 16ch WASAPI interface giving garbage wav file #549

Closed dts350z closed 2 years ago

dts350z commented 2 years ago

I have a working WASAPI interface set for 16 ch. 48000 KHz 24 bits. I can record from this interface in audio applications without issue.

In trying the simple_capture example with the settings to match the device, the output wav is garbage:

image

What it should look like:

image

Here is the debug output:

miniaudioExamples\x64\Debug>simple_capture.exe out.wav DEBUG: Loading library: ole32.dll DEBUG: Loading symbol: CoInitializeEx DEBUG: Loading symbol: CoUninitialize DEBUG: Loading symbol: CoCreateInstance DEBUG: Loading symbol: CoTaskMemFree DEBUG: Loading symbol: PropVariantClear DEBUG: Loading symbol: StringFromGUID2 DEBUG: Loading library: user32.dll DEBUG: Loading symbol: GetForegroundWindow DEBUG: Loading symbol: GetDesktopWindow DEBUG: Loading library: advapi32.dll DEBUG: Loading symbol: RegOpenKeyExA DEBUG: Loading symbol: RegCloseKey DEBUG: Loading symbol: RegQueryValueExA DEBUG: Attempting to initialize WASAPI backend... DEBUG: Loading library: kernel32.dll DEBUG: Loading symbol: VerifyVersionInfoW DEBUG: Loading symbol: VerSetConditionMask DEBUG: System Architecture: DEBUG: Endian: LE DEBUG: SSE2: YES DEBUG: AVX2: YES DEBUG: NEON: NO DEBUG: [WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=480) DEBUG: defaultPeriodInFrames=480 DEBUG: fundamentalPeriodInFrames=480 DEBUG: minPeriodInFrames=480 DEBUG: maxPeriodInFrames=480 DEBUG: [WASAPI] Using IAudioClient3 DEBUG: periodSizeInFramesOut=480 INFO: [WASAPI] INFO: Internal Record (nerds.de LoopBeAudio - Internal Audio Ports) (Capture) INFO: Format: 32-bit IEEE Floating Point -> 24-bit Signed Integer (Tightly Packed) INFO: Channels: 16 -> 16 INFO: Sample Rate: 48000 -> 48000 INFO: Buffer Size: 480*3 (1440) INFO: Conversion: INFO: Pre Format Conversion: NO INFO: Post Format Conversion: YES INFO: Channel Routing: YES INFO: Resampling: NO INFO: Passthrough: NO Press Enter to stop recording... DEBUG: [WASAPI] Data discontinuity (possible overrun). Attempting recovery. mappedBufferCaptureCap=480

mackron commented 2 years ago

Can you post the exact code here so I can see how you've set up your config and the encoder? Make sure the format you specify on the device matches the encoder.

Also, unlikely to be the issue here, but I fixed some issues relating to channel mapping. It's in the dev branch if you want to try that.

dts350z commented 2 years ago

Below is the code, and you can also see (now commented out) other configs I have tried. Those yield different, but still incorrect results.

The device is "locked" at 16 ch, 24 bit, 48000 Hz:

image

image

FYI you can get a free trial of this device: https://www.nerds.de/en/loopbeaudio.html

I will try the dev branch presently. Turning off any channel mapping seems a logical step, but it wasn't clear how to do that with the "low level interface" approach in simple_capture.c

Thanks

/*
Demonstrates how to capture data from a microphone using the low-level API.

This example simply captures data from your default microphone until you press Enter. The output is saved to the file
specified on the command line.

Capturing works in a very similar way to playback. The only difference is the direction of data movement. Instead of
the application sending data to the device, the device will send data to the application. This example just writes the
data received by the microphone straight to a WAV file.
*/
#define MA_DEBUG_OUTPUT
#define MINIAUDIO_IMPLEMENTATION
#define MA_ENABLE_ONLY_SPECIFIC_BACKEND
#define MA_ENABLE_WASAPI

#include "../miniaudio.h"

#include <stdlib.h>
#include <stdio.h>

void data_callback(ma_device* pDevice, void* pOutput, const void* pInput, ma_uint32 frameCount)
{
    ma_encoder* pEncoder = (ma_encoder*)pDevice->pUserData;
    MA_ASSERT(pEncoder != NULL);

    ma_encoder_write_pcm_frames(pEncoder, pInput, frameCount, NULL);

    (void)pOutput;
}

int main(int argc, char** argv)
{
    ma_result result;
    ma_encoder_config encoderConfig;
    ma_encoder encoder;
    ma_device_config deviceConfig;
    ma_device device;

    if (argc < 2) {
        printf("No output file.\n");
        return -1;
    }

    encoderConfig = ma_encoder_config_init(ma_encoding_format_wav, ma_format_s24, 16, 48000);

    if (ma_encoder_init_file(argv[1], &encoderConfig, &encoder) != MA_SUCCESS) {
        printf("Failed to initialize output file.\n");
        return -1;
    }

    deviceConfig = ma_device_config_init(ma_device_type_capture);

    deviceConfig.capture.pDeviceID = 0;
    //deviceConfig.capture.format   = ma_format_unknown;
    //deviceConfig.capture.channels = 0;
    //deviceConfig.sampleRate = 0;
    deviceConfig.capture.format = encoder.config.format;
    deviceConfig.capture.channels = encoder.config.channels;
    deviceConfig.sampleRate       = encoder.config.sampleRate;
    deviceConfig.dataCallback     = data_callback;
    deviceConfig.pUserData        = &encoder;

    result = ma_device_init(NULL, &deviceConfig, &device);
    if (result != MA_SUCCESS) {
        printf("Failed to initialize capture device.\n");
        return -2;
    }

    result = ma_device_start(&device);
    if (result != MA_SUCCESS) {
        ma_device_uninit(&device);
        printf("Failed to start device.\n");
        return -3;
    }

    printf("Press Enter to stop recording...\n");
    getchar();

    ma_device_uninit(&device);
    ma_encoder_uninit(&encoder);

    return 0;
}
dts350z commented 2 years ago

Good News, the dev branch appears to work correctly with my device:

image

miniaudio-dev\examples\simple_capture_dev\x64\Debug>simple_capture_dev.exe out.wav
DEBUG: Loading library: ole32.dll
DEBUG: Loading symbol: CoInitializeEx
DEBUG: Loading symbol: CoUninitialize
DEBUG: Loading symbol: CoCreateInstance
DEBUG: Loading symbol: CoTaskMemFree
DEBUG: Loading symbol: PropVariantClear
DEBUG: Loading symbol: StringFromGUID2
DEBUG: Loading library: user32.dll
DEBUG: Loading symbol: GetForegroundWindow
DEBUG: Loading symbol: GetDesktopWindow
DEBUG: Loading library: advapi32.dll
DEBUG: Loading symbol: RegOpenKeyExA
DEBUG: Loading symbol: RegCloseKey
DEBUG: Loading symbol: RegQueryValueExA
DEBUG: Attempting to initialize WASAPI backend...
DEBUG: Loading library: kernel32.dll
DEBUG: Loading symbol: VerifyVersionInfoW
DEBUG: Loading symbol: VerSetConditionMask
DEBUG: Loading library: avrt.dll
DEBUG: Loading symbol: AvSetMmThreadCharacteristicsW
DEBUG: Loading symbol: AvRevertMmThreadCharacteristics
DEBUG: System Architecture:
DEBUG:   Endian: LE
DEBUG:   SSE2:   YES
DEBUG:   AVX2:   YES
DEBUG:   NEON:   NO
DEBUG: [WASAPI] Trying IAudioClient3_InitializeSharedAudioStream(actualPeriodInFrames=480)
DEBUG:     defaultPeriodInFrames=480
DEBUG:     fundamentalPeriodInFrames=480
DEBUG:     minPeriodInFrames=480
DEBUG:     maxPeriodInFrames=480
DEBUG: [WASAPI] Using IAudioClient3
DEBUG:     periodSizeInFramesOut=480
INFO: [WASAPI]
INFO:   Internal Record (nerds.de LoopBeAudio - Internal Audio Ports) (Capture)
INFO:     Format:      32-bit IEEE Floating Point -> 24-bit Signed Integer (Tightly Packed)
INFO:     Channels:    16 -> 16
INFO:     Sample Rate: 48000 -> 48000
INFO:     Buffer Size: 480*3 (1440)
INFO:     Conversion:
INFO:       Pre Format Conversion:  NO
INFO:       Post Format Conversion: YES
INFO:       Channel Routing:        NO
INFO:       Resampling:             NO
INFO:       Passthrough:            NO
INFO:       Channel Map In:         {CHANNEL_FRONT_LEFT CHANNEL_FRONT_RIGHT CHANNEL_FRONT_CENTER CHANNEL_LFE CHANNEL_BACK_LEFT CHANNEL_BACK_RIGHT CHANNEL_SIDE_LEFT CHANNEL_SIDE_RIGHT CHANNEL_AUX_0 CHANNEL_AUX_1 CHANNEL_AUX_2 CHANNEL_AUX_3 CHANNEL_AUX_4 CHANNEL_AUX_5 CHANNEL_AUX_6 CHANNEL_AUX_7}
INFO:       Channel Map Out:        {CHANNEL_FRONT_LEFT CHANNEL_FRONT_RIGHT CHANNEL_FRONT_CENTER CHANNEL_LFE CHANNEL_BACK_LEFT CHANNEL_BACK_RIGHT CHANNEL_SIDE_LEFT CHANNEL_SIDE_RIGHT CHANNEL_AUX_0 CHANNEL_AUX_1 CHANNEL_AUX_2 CHANNEL_AUX_3 CHANNEL_AUX_4 CHANNEL_AUX_5 CHANNEL_AUX_6 CHANNEL_AUX_7}
Press Enter to stop recording...
DEBUG: [WASAPI] Data discontinuity (possible overrun). Attempting recovery. mappedBufferCaptureCap=480
mackron commented 2 years ago

Thanks for checking the dev branch. Glad that's fixed it for you. Will need to get a release done soon.

mackron commented 2 years ago

I've done a new release which includes the fix for this issue. Thanks for reporting.