HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
win32_wave_device.hpp
1// Copyright Take Vos 2022.
2// Distributed under the Boost Software License, Version 1.0.
3// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5#pragma once
6
7#include "audio_direction.hpp"
8#include "win32_device_interface.hpp"
9#include "../macros.hpp"
10#include <string>
11#include <coroutine>
12
13hi_export_module(hikogui.audio.win32_wave_device);
14
15hi_export namespace hi { inline namespace v1 {
16
17hi_export class win32_wave_device {
18public:
19 win32_wave_device(UINT id, audio_direction direction) : _id(id), _direction(direction)
20 {
21 hi_assert(_direction == audio_direction::input or _direction == audio_direction::output);
22 }
23
26 [[nodiscard]] std::string end_point_id() const
27 {
28 return message_string(DRV_QUERYFUNCTIONINSTANCEID, DRV_QUERYFUNCTIONINSTANCEIDSIZE);
29 }
30
36 {
37 auto device_name = message_string(DRV_QUERYDEVICEINTERFACE, DRV_QUERYDEVICEINTERFACESIZE);
38 return win32_device_interface{device_name};
39 }
40
41 [[nodiscard]] static UINT num_devices(audio_direction direction) noexcept
42 {
43 return direction == audio_direction::input ? waveInGetNumDevs() : waveOutGetNumDevs();
44 }
45
46 [[nodiscard]] static generator<win32_wave_device> enumerate(audio_direction direction) noexcept
47 {
48 auto num = num_devices(direction);
49
50 for (UINT id = 0; id != num; ++id) {
51 co_yield win32_wave_device{id, direction};
52 }
53 }
54
55 [[nodiscard]] static win32_wave_device find_matching_end_point(audio_direction direction, std::string end_point_id)
56 {
57 for (auto wave_api : enumerate(direction)) {
58 if (wave_api.end_point_id() == end_point_id) {
59 return wave_api;
60 }
61 }
62 throw io_error(std::format("Could not find matching wave device for end-point-id {}", end_point_id));
63 }
64
65private:
66 UINT _id;
67 audio_direction _direction;
68
69 [[nodiscard]] std::wstring message_wstring(UINT message_id, UINT size_message_id) const
70 {
71 DWORD size = 0;
72 {
73 auto const result = _direction == audio_direction::input ?
74 waveInMessage((HWAVEIN)IntToPtr(_id), size_message_id, std::bit_cast<DWORD_PTR>(&size), NULL) :
75 waveOutMessage((HWAVEOUT)IntToPtr(_id), size_message_id, std::bit_cast<DWORD_PTR>(&size), NULL);
76
77 if (result != MMSYSERR_NOERROR) {
78 throw io_error(std::format(
79 "Could not get win32_wave_api wstring-message {} for wave-device-id:{}:{}",
80 size_message_id,
81 _direction,
82 _id));
83 }
84 }
85
86 // The length is in bytes, including the terminating wchar_t{}.
87 hi_assert(size > 0 and size % sizeof(wchar_t) == 0);
88 auto str = std::wstring(size / sizeof(wchar_t) - 1, wchar_t{});
89 {
90 auto const result = _direction == audio_direction::input ?
91 waveInMessage((HWAVEIN)IntToPtr(_id), message_id, std::bit_cast<DWORD_PTR>(str.data()), size) :
92 waveOutMessage((HWAVEOUT)IntToPtr(_id), message_id, std::bit_cast<DWORD_PTR>(str.data()), size);
93
94 if (result != MMSYSERR_NOERROR) {
95 throw io_error(std::format(
96 "Could not get win32_wave_api wstring-message {} for wave-device-id:{}:{}", message_id, _direction, _id));
97 }
98 }
99
100 return str;
101 }
102
103 [[nodiscard]] std::string message_string(UINT message_id, UINT size_message_id) const
104 {
105 return to_string(message_wstring(message_id, size_message_id));
106 }
107};
108
109}} // namespace hi::inline v1
STL namespace.
The HikoGUI namespace.
Definition array_generic.hpp:20
DOXYGEN BUG.
Definition algorithm_misc.hpp:20
Definition win32_device_interface.hpp:19
Definition win32_wave_device.hpp:17
win32_device_interface open_device_interface() const
Open the audio device.
Definition win32_wave_device.hpp:35
std::string end_point_id() const
The end-point-id matching end-point ids of the modern Core Audio MMDevice API.
Definition win32_wave_device.hpp:26
T to_string(T... args)