Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wasapi driver outputs device names encoded in Windows ANSI default codepage #1322

Closed
pedrolcl opened this issue Apr 27, 2024 · 5 comments
Closed
Labels

Comments

@pedrolcl
Copy link
Contributor

FluidSynth version

$ ./fluidsynth.exe --version
FluidSynth runtime version 2.3.5
Copyright (C) 2000-2024 Peter Hanappe and others.
Distributed under the LGPL license.
SoundFont(R) is a registered trademark of Creative Technology Ltd.

FluidSynth executable version 2.3.5
Sample type=double

Describe the bug

This comes from a Qsynth ticket: Device initialization fails when audio driver is set to WASAPI and output destination is other than default. rncbc/qsynth#82

The reporter includes a screenshot where the selection of audio devices appears corrupted, due to inconsistent character decoding.
When the users tries to select any audio device other than "default", the initialization of the audio driver fails with an error message:

Qsynth1: Failed to create the audio driver (wasapi). Cannot continue without it.

Expected behavior

The list of available audio devices is correctly presented to the user, and any device can be selected and initialized, if all other parameters are supported.

Steps to reproduce

The original reporter has a Japanese Windows 11 version, using codepage 932. I've been able to reproduce the issue renaming in my system (which uses codepage 1252) the audio devices to include some tricky characters.

Additional context

All other Fluidsynth MIDI and audio drivers report the audio devices as settings options encoded as UTF-8 except the Wasapi driver, that uses the default windows codepage.

$ grep "WideCharToMultiByte" src/*/*
src/drivers/fluid_wasapi.c:        nsz = WideCharToMultiByte(CP_ACP, 0, var.pwszVal, -1, 0, 0, 0, 0);
src/drivers/fluid_wasapi.c:        WideCharToMultiByte(CP_ACP, 0, var.pwszVal, -1, name, nsz, 0, 0);
src/drivers/fluid_wasapi.c:    nsz = WideCharToMultiByte(CP_ACP, 0, var.pwszVal, -1, 0, 0, 0, 0);
src/drivers/fluid_wasapi.c:    WideCharToMultiByte(CP_ACP, 0, var.pwszVal, -1, name, nsz, 0, 0);
src/drivers/fluid_waveout.c:            WideCharToMultiByte(CP_UTF8, 0, caps.szPname, -1, dev_name, MAXPNAMELEN, 0, 0);
src/drivers/fluid_winmidi.c:    WideCharToMultiByte(CP_UTF8, 0, wStr, -1, strError, MAXERRORLENGTH, 0, 0);
src/utils/fluid_sys.c:    WideCharToMultiByte(CP_UTF8, 0, err, -1, ascii_err, sizeof(ascii_err)/sizeof(ascii_err[0]), 0, 0);
$ grep "MultiByteToWideChar" src/*/*
src/drivers/fluid_waveout.c:        MultiByteToWideChar(CP_UTF8, 0, dev_name, -1, lpwDevName, MAXPNAMELEN);
src/drivers/fluid_winmidi.c:                    MultiByteToWideChar(CP_UTF8, 0, dev_name, -1, wDevName, MAXPNAMELEN);
src/utils/fluid_sys.c:    if ((length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, NULL, 0)) == 0)
src/utils/fluid_sys.c:        FLUID_LOG(FLUID_ERR, "Unable to perform MultiByteToWideChar() conversion for filename '%s'. Error was: '%s'", filename, fluid_get_windows_error());
src/utils/fluid_sys.c:    MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, filename, -1, wpath, length);
src/utils/fluid_sys.c:    if ((length = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, NULL, 0)) == 0)
src/utils/fluid_sys.c:        FLUID_LOG(FLUID_ERR, "Unable to perform MultiByteToWideChar() conversion for mode '%s'. Error was: '%s'", mode, fluid_get_windows_error());
src/utils/fluid_sys.c:    MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, mode, -1, wmode, length);

WideCharToMultiByte() is a Win32 API function to convert Unicode strings (Wide Chars) used internally by Windows into multibyte encodings (or single byte, for what is worth). When using the first argument CP_ACP, its output is using the system default Windows ANSI code page. This is what fluid_wasapi.c is doing. All other windows drivers use CP_UTF8 as the first argument.

The documentation for settings does not specify anything about the encoding for string options. This should be fixed as well.

And finally, the CLI fluidsynth.exe needs to be fixed as well to output readable text when processing the arguments -a wasapi -Q, because it will output garbage to the terminal if the wasapi driver is fixed to use CP_UTF8.

@pedrolcl pedrolcl added the bug label Apr 27, 2024
@derselbst
Copy link
Member

I didn't had a deeper look into this. For the context, it originally was UTF8, but changed in the context of #984.

@pedrolcl
Copy link
Contributor Author

I didn't had a deeper look into this. For the context, it originally was UTF8, but changed in the context of #984.

It is an unfortunate regression. The command line arguments conversion to UTF-8 are correct, but on the other hand the console output should have been also declared as Unicode, instead of taking back the device names to the ANSI code page.

@derselbst : We need a Fluidsynth declaration of Unicode allegiance.

See also: https://learn.microsoft.com/en-us/windows/console/console-code-pages

Tip

It is recommended for all new and updated command-line applications to avoid code pages and use Unicode. UTF-16 formatted text can be sent to the W family of console APIs. UTF-8 formatted text can be sent to the A family of console APIs after ensuring the code page is first set to 65001 (CP_UTF8) with the SetConsoleCP and SetConsoleOutputCP functions.

@pedrolcl
Copy link
Contributor Author

Other windows driver needs to be converted to UTF8 as well:

  • dsound

And these drivers have already a _UNICODE macro to do the job, but there is no support in CMake for this symbol?

  • waveout
  • winmidi

@derselbst
Copy link
Member

@derselbst : We need a Fluidsynth declaration of Unicode allegiance.

Sure, I'm all in favor of documenting that the device names of settings like audio.wasapi.device are encoded as UTF-8.

@pedrolcl
Copy link
Contributor Author

And these drivers have already a _UNICODE macro to do the job, but there is no support in CMake for this symbol?

* waveout

* winmidi

Defining the symbol _UNICODE, fluidsynth doesn't compile anymore. This will be more work than I thought.

DominusExult added a commit to DominusExult/fluidsynth-sans-glib that referenced this issue Jul 29, 2024
* master: (33 commits)
  Remove interpolation of IIR filter coefficients (FluidSynth#1345)
  Add OS/2 KAI audio driver
  Fix behavior of volume envelope delay phase
  Fix chorus when compiling with single precision (FluidSynth#1339)
  Update docs about XG bank selection logic
  Fix a few compiler warnings
  Fix linkage against gobject
  Fix mixed declaration
  Log NRPNs in verbose mode
  Update documentation of synth.device-id
  Access to synth->bank_select not guarded by mutex
  when processing command line options: -o setting=value, the value is converted to UTF8
  review findings
  Documentation updated (settings, about utf-8 encoding) C++ example updated
  drivers: winmidi,waveout and dsound using utf8 options Unicode support enabled in CMake script and CLI utility
  Fixed  wasapi driver; encode device names as CP_UTF8 Solves FluidSynth#1322
  Fix an import library is treated as a static library on OS/2 (FluidSynth#1321)
  Bump the github-actions group with 2 updates
  Keep GitHub Actions up to date with GitHub's Dependabot
  Minor fixups for MSYS2 CI (FluidSynth#1317)
  ...

# Conflicts:
#	CMakeLists.txt
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants