1
1
#pragma once
2
2
#include < ossia/detail/config.hpp>
3
3
4
- // #if 1 || defined(OSSIA_ENABLE_MINIAUDIO)
4
+ #if __has_include(<miniaudio.h>)
5
+ #define OSSIA_ENABLE_MINIAUDIO 1
5
6
#define MINIAUDIO_IMPLEMENTATION
6
7
#if defined(__APPLE__)
7
8
#define MA_NO_RUNTIME_LINKING 1
16
17
#define MA_NO_NODE_GRAPH 1
17
18
#define MA_NO_GENERATION 1
18
19
#define MA_API
19
- # if __has_include(<miniaudio.h>)
20
+
20
21
#include < ossia/audio/audio_engine.hpp>
21
22
#include < ossia/detail/thread.hpp>
22
23
23
- #include < miniaudio.h >
24
+ #include < kfr/base/conversion.hpp >
24
25
25
- #include < iostream >
26
+ #include < miniaudio.h >
26
27
27
28
#define OSSIA_AUDIO_MINIAUDIO 1
28
29
29
30
namespace ossia
30
31
{
32
+ struct miniaudio_context
33
+ {
34
+ ma_context context;
35
+ };
36
+
31
37
class miniaudio_engine final : public audio_engine
32
38
{
39
+
33
40
public:
41
+ std::vector<const ma_device_info*> devices;
42
+ bool is_duplex (const ma_device_id& card_in, const ma_device_id& card_out)
43
+ {
44
+ #if defined(__APPLE__)
45
+ return true ;
46
+ std::string_view i = card_in.coreaudio ;
47
+ std::string_view o = card_out.coreaudio ;
48
+ if (i.length () != o.length () || i.empty () || o.empty ())
49
+ return false ;
50
+ if (i.substr (0 , i.size () - 1 ) == o.substr (0 , o.size () - 1 ))
51
+ return true ;
52
+
53
+ #endif
54
+ return memcmp (&card_in, &card_out, sizeof (ma_device_id)) == 0 ;
55
+ }
34
56
miniaudio_engine (
35
- std::string name, std::string card_in, std::string card_out, int inputs,
36
- int outputs, int rate, int bs)
57
+ std::shared_ptr<miniaudio_context> ctx, std::string name,
58
+ const ma_device_id& card_in, const ma_device_id& card_out, int inputs, int outputs,
59
+ int rate, int bs)
60
+ : m_ctx{std::move (ctx)}
37
61
{
38
- ma_device_config config = ma_device_config_init (ma_device_type_duplex);
62
+ ma_device_type dtype = ma_device_type_duplex;
63
+ if (inputs == 0 )
64
+ dtype = ma_device_type_playback;
65
+ else if (outputs == 0 )
66
+ dtype = ma_device_type_capture;
67
+
68
+ ma_device_config config = ma_device_config_init (dtype);
69
+
39
70
config.sampleRate = rate;
40
71
config.periodSizeInFrames = bs;
41
- config.playback .channels = outputs;
42
- config.playback .format = ma_format_f32;
43
- config.capture .channels = inputs;
44
- config.capture .format = ma_format_f32;
72
+
73
+ if (outputs > 0 )
74
+ {
75
+ config.playback .pDeviceID = &card_out;
76
+ config.playback .channels = outputs;
77
+ config.playback .format = ma_format_f32;
78
+ // config.playback.shareMode = ma_share_mode_exclusive;
79
+ }
80
+
81
+ if (inputs > 0 )
82
+ {
83
+ config.capture .pDeviceID = &card_in;
84
+ config.capture .channels = inputs;
85
+ config.capture .format = ma_format_f32;
86
+ // config.capture.shareMode = ma_share_mode_exclusive;
87
+ }
45
88
46
89
config.dataCallback = callback;
47
90
@@ -50,11 +93,19 @@ class miniaudio_engine final : public audio_engine
50
93
config.noClip = false ;
51
94
config.noDisableDenormals = false ;
52
95
config.noPreSilencedOutputBuffer = false ;
96
+
53
97
config.pUserData = this ;
54
98
55
- if (ma_device_init (NULL , &config, &m_stream) != MA_SUCCESS)
99
+ if (ma_device_init (&m_ctx-> context , &config, &m_stream) != MA_SUCCESS)
56
100
throw std::runtime_error (" Cannot initialize miniaudio" );
57
- ma_device_start (&m_stream);
101
+
102
+ if (ma_device_start (&m_stream) != MA_SUCCESS)
103
+ throw std::runtime_error (" Cannot start miniaudio" );
104
+
105
+ this ->effective_buffer_size = bs;
106
+ this ->effective_sample_rate = rate;
107
+ this ->effective_inputs = inputs;
108
+ this ->effective_outputs = outputs;
58
109
}
59
110
60
111
bool running () const override
@@ -91,20 +142,29 @@ class miniaudio_engine final : public audio_engine
91
142
return ;
92
143
}
93
144
94
- auto float_input = ((float * const *)input);
95
- auto float_output = ((float **)output);
145
+ float ins_data[self.effective_inputs * nframes];
146
+ float * ins[self.effective_inputs + 2 ];
147
+ for (int i = 0 ; i < self.effective_inputs ; i++)
148
+ ins[i] = ins_data + i * nframes;
149
+ kfr::deinterleave (ins, (float *)input, self.effective_inputs , nframes);
150
+
151
+ float outs_data[self.effective_outputs * nframes];
152
+ std::memset (outs_data, 0 , sizeof (float ) * self.effective_outputs * nframes);
153
+ float * outs[self.effective_outputs + 2 ];
154
+ for (int i = 0 ; i < self.effective_outputs ; i++)
155
+ outs[i] = outs_data + i * nframes;
96
156
97
- ossia::audio_tick_state ts{float_input,
98
- float_output,
99
- self.effective_inputs ,
100
- self.effective_outputs ,
101
- nframes,
102
- 0 };
157
+ ossia::audio_tick_state ts{(float * const *)ins, outs, self.effective_inputs ,
158
+ self.effective_outputs , nframes, 0 }; // FIXME timing
103
159
self.audio_tick (ts);
104
160
105
161
self.tick_end ();
162
+
163
+ kfr::interleave (
164
+ (float *)output, (const float **)outs, self.effective_outputs , nframes);
106
165
}
107
166
167
+ std::shared_ptr<miniaudio_context> m_ctx;
108
168
ma_device m_stream;
109
169
};
110
170
}
0 commit comments