Skip to content

Commit 9035a3a

Browse files
committed
miniaudio: finish implementation
1 parent 1dfa430 commit 9035a3a

File tree

1 file changed

+81
-21
lines changed

1 file changed

+81
-21
lines changed

src/ossia/audio/miniaudio_protocol.hpp

+81-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
#pragma once
22
#include <ossia/detail/config.hpp>
33

4-
//#if 1 || defined(OSSIA_ENABLE_MINIAUDIO)
4+
#if __has_include(<miniaudio.h>)
5+
#define OSSIA_ENABLE_MINIAUDIO 1
56
#define MINIAUDIO_IMPLEMENTATION
67
#if defined(__APPLE__)
78
#define MA_NO_RUNTIME_LINKING 1
@@ -16,32 +17,74 @@
1617
#define MA_NO_NODE_GRAPH 1
1718
#define MA_NO_GENERATION 1
1819
#define MA_API
19-
#if __has_include(<miniaudio.h>)
20+
2021
#include <ossia/audio/audio_engine.hpp>
2122
#include <ossia/detail/thread.hpp>
2223

23-
#include <miniaudio.h>
24+
#include <kfr/base/conversion.hpp>
2425

25-
#include <iostream>
26+
#include <miniaudio.h>
2627

2728
#define OSSIA_AUDIO_MINIAUDIO 1
2829

2930
namespace ossia
3031
{
32+
struct miniaudio_context
33+
{
34+
ma_context context;
35+
};
36+
3137
class miniaudio_engine final : public audio_engine
3238
{
39+
3340
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+
}
3456
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)}
3761
{
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+
3970
config.sampleRate = rate;
4071
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+
}
4588

4689
config.dataCallback = callback;
4790

@@ -50,11 +93,19 @@ class miniaudio_engine final : public audio_engine
5093
config.noClip = false;
5194
config.noDisableDenormals = false;
5295
config.noPreSilencedOutputBuffer = false;
96+
5397
config.pUserData = this;
5498

55-
if(ma_device_init(NULL, &config, &m_stream) != MA_SUCCESS)
99+
if(ma_device_init(&m_ctx->context, &config, &m_stream) != MA_SUCCESS)
56100
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;
58109
}
59110

60111
bool running() const override
@@ -91,20 +142,29 @@ class miniaudio_engine final : public audio_engine
91142
return;
92143
}
93144

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;
96156

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
103159
self.audio_tick(ts);
104160

105161
self.tick_end();
162+
163+
kfr::interleave(
164+
(float*)output, (const float**)outs, self.effective_outputs, nframes);
106165
}
107166

167+
std::shared_ptr<miniaudio_context> m_ctx;
108168
ma_device m_stream;
109169
};
110170
}

0 commit comments

Comments
 (0)