• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ossia / libossia / 37466882128

06 Oct 2026 12:55PM UTC coverage: 52.78% (+0.4%) from 52.335%
37466882128

push

github

jcelerier
alsa: a direction without channels is not opened

With no input channels, the capture device was still opened: on a card
that cannot record, or one in use, the engine failed to start. The play
and capture names were also passed in each other's place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TcLJ4VuB2nzXbazQb9nyC1

32356 of 61304 relevant lines covered (52.78%)

174256.98 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.82
/tests/Dataflow/TokenRequestTest.cpp
1
#include "../Editor/TestUtils.hpp"
2

3
#include <ossia/detail/config.hpp>
4

5
#include <ossia/dataflow/token_request.hpp>
6

7
#include "include_catch.hpp"
8

9
#include <cmath>
10
#include <iterator>
11
#include <utility>
12
#include <vector>
13
TEST_CASE("test_loops_integer", "test_loops_integer")
1 ✔
14
{
15
  using namespace ossia;
16

17
  token_request r;
1 ✔
18
  r.prev_date = 0_tv;
1 ✔
19
  r.date = 100_tv;
1 ✔
20

21
  token_request_vec vec;
1 ✔
22
  r.loop(
1 ✔
23
      0_tv, 10_tv, [&](auto& req) { vec.push_back(req); }, [](const auto&) {});
20 ✔
24

25
  simple_token_request_vec expected{
26
      {.prev_date = 0_tv, .date = 10_tv, .offset = 0_tv},
27
      {.prev_date = 0_tv, .date = 10_tv, .offset = 10_tv},
28
      {.prev_date = 0_tv, .date = 10_tv, .offset = 20_tv},
29
      {.prev_date = 0_tv, .date = 10_tv, .offset = 30_tv},
30
      {.prev_date = 0_tv, .date = 10_tv, .offset = 40_tv},
31
      {.prev_date = 0_tv, .date = 10_tv, .offset = 50_tv},
32
      {.prev_date = 0_tv, .date = 10_tv, .offset = 60_tv},
33
      {.prev_date = 0_tv, .date = 10_tv, .offset = 70_tv},
34
      {.prev_date = 0_tv, .date = 10_tv, .offset = 80_tv},
35
      {.prev_date = 0_tv, .date = 10_tv, .offset = 90_tv}};
1 ✔
36

37
  REQUIRE(expected == vec);
1 ✔
38
}
1 ✔
39

40
TEST_CASE("test_loops_fract", "test_loops_fract")
1 ✔
41
{
42
  using namespace ossia;
43

44
  token_request r;
1 ✔
45
  r.prev_date = 0_tv;
1 ✔
46
  r.date = 97_tv;
1 ✔
47

48
  token_request_vec vec;
1 ✔
49
  r.loop(
1 ✔
50
      0_tv, 10_tv, [&](auto& req) { vec.push_back(req); }, [](const auto&) {});
19 ✔
51

52
  simple_token_request_vec expected{
53
      {.prev_date = 0_tv, .date = 10_tv, .offset = 0_tv},
54
      {.prev_date = 0_tv, .date = 10_tv, .offset = 10_tv},
55
      {.prev_date = 0_tv, .date = 10_tv, .offset = 20_tv},
56
      {.prev_date = 0_tv, .date = 10_tv, .offset = 30_tv},
57
      {.prev_date = 0_tv, .date = 10_tv, .offset = 40_tv},
58
      {.prev_date = 0_tv, .date = 10_tv, .offset = 50_tv},
59
      {.prev_date = 0_tv, .date = 10_tv, .offset = 60_tv},
60
      {.prev_date = 0_tv, .date = 10_tv, .offset = 70_tv},
61
      {.prev_date = 0_tv, .date = 10_tv, .offset = 80_tv},
62
      {.prev_date = 0_tv, .date = 7_tv, .offset = 90_tv}};
1 ✔
63

64
  REQUIRE(expected == vec);
1 ✔
65
}
1 ✔
66

67
TEST_CASE("test_loops_offset", "test_loops_offset")
1 ✔
68
{
69
  using namespace ossia;
70

71
  token_request r;
1 ✔
72
  r.prev_date = 2_tv;
1 ✔
73
  r.date = 12_tv;
1 ✔
74

75
  token_request_vec vec;
1 ✔
76
  r.loop(
1 ✔
77
      0_tv, 5_tv, [&](auto& req) { vec.push_back(req); }, [](const auto&) {});
5 ✔
78

79
  simple_token_request_vec expected{
80
      {.prev_date = 2_tv, .date = 5_tv, .offset = 0_tv},
81
      {.prev_date = 0_tv, .date = 5_tv, .offset = 3_tv},
82
      {.prev_date = 0_tv, .date = 2_tv, .offset = 8_tv},
83
  };
1 ✔
84

85
  REQUIRE(expected == vec);
1 ✔
86
}
1 ✔
87

88
TEST_CASE("test_loops_smaller", "test_loops_smaller")
1 ✔
89
{
90
  using namespace ossia;
91

92
  token_request r;
1 ✔
93
  r.prev_date = 0_tv;
1 ✔
94
  r.date = 15_tv;
1 ✔
95

96
  token_request_vec vec;
1 ✔
97
  r.loop(
1 ✔
98
      0_tv, 20_tv, [&](auto& req) { vec.push_back(req); }, [](const auto&) {});
1 ✔
99

100
  simple_token_request_vec expected{{.prev_date = 0_tv, .date = 15_tv, .offset = 0_tv}};
1 ✔
101

102
  REQUIRE(expected == vec);
1 ✔
103
}
1 ✔
104

105
TEST_CASE("test_loops_mid", "test_loops_mid")
1 ✔
106
{
107
  using namespace ossia;
108

109
  token_request r;
1 ✔
110
  r.prev_date = 15_tv;
1 ✔
111
  r.date = 30_tv;
1 ✔
112

113
  token_request_vec vec;
1 ✔
114
  r.loop(
1 ✔
115
      0_tv, 20_tv, [&](auto& req) { vec.push_back(req); }, [](const auto&) {});
3 ✔
116

117
  simple_token_request_vec expected{
118
      {.prev_date = 15_tv, .date = 20_tv, .offset = 0_tv},
119
      {.prev_date = 0_tv, .date = 10_tv, .offset = 5_tv}};
1 ✔
120

121
  REQUIRE(expected == vec);
1 ✔
122
}
1 ✔
123

124
TEST_CASE("test_loops_still", "test_loops_still")
1 ✔
125
{
126
  // Speed 0: a looping process still runs once, at its position in the loop.
127
  using namespace ossia;
128

129
  token_request r;
1 ✔
130
  r.prev_date = 35_tv;
1 ✔
131
  r.date = 35_tv;
1 ✔
132

133
  token_request_vec vec;
1 ✔
134
  int transports = 0;
1 ✔
135
  r.loop(
1 ✔
136
      5_tv, 20_tv, [&](auto& req) { vec.push_back(req); },
1 ✔
137
      [&](const auto&) { transports++; });
×
138

139
  simple_token_request_vec expected{{.prev_date = 20_tv, .date = 20_tv, .offset = 0_tv}};
1 ✔
140

141
  REQUIRE(expected == vec);
1 ✔
142
  REQUIRE(transports == 0);
1 ✔
143
}
1 ✔
144

145
TEST_CASE("test_musical_quantization", "test_musical_quantization")
1 ✔
146
{
147
  using namespace ossia;
148

149
  token_request r;
1 ✔
150
  r.prev_date = 0_tv;
1 ✔
151
  r.date = 2048000_tv;
1 ✔
152
  r.musical_end_last_bar = 0.005804985827664399;
1 ✔
153
  r.musical_end_position = 0.005804985827664399;
1 ✔
154

155
  auto res = r.get_quantification_date(8.0);
1 ✔
156
  REQUIRE(res == 0_tv);
1 ✔
157
}
1 ✔
158

159
namespace
160
{
161
using date_list = std::vector<std::pair<int64_t, int64_t>>;
162

163
//! A tick covering [prev; date[ in model time and [mstart; mend[ in quarters.
164
ossia::token_request musical_tick(
15 ✔
165
    int64_t prev, int64_t date, double mstart, double mend, uint16_t num = 4, uint16_t denom = 4)
166
{
167
  ossia::token_request t;
15 ✔
168
  t.prev_date = ossia::time_value{prev};
15 ✔
169
  t.date = ossia::time_value{date};
15 ✔
170
  t.musical_start_position = mstart;
15 ✔
171
  t.musical_end_position = mend;
15 ✔
172
  t.musical_start_last_bar = 0.;
15 ✔
173
  t.musical_start_last_signature = 0.;
15 ✔
174
  t.signature = ossia::time_signature{num, denom};
15 ✔
175
  return t;
15 ✔
176
}
177

178
date_list dates(const ossia::quantification_points& p)
9 ✔
179
{
180
  date_list out;
9 ✔
181
  for(auto& q : p)
46 ✔
182
    out.emplace_back(q.date.impl, q.index);
14 ✔
183
  return out;
9 ✔
184
}
×
185
}
186

187
TEST_CASE("quantification_dates_empty_tick", "quantification_dates")
1 ✔
188
{
189
  auto t = musical_tick(100, 100, 0., 1.);
1 ✔
190
  REQUIRE(t.get_quantification_dates(4).empty());
1 ✔
191
}
1 ✔
192

193
TEST_CASE("quantification_dates_no_rate", "quantification_dates")
1 ✔
194
{
195
  // A null or negative rate means "as soon as possible".
196
  auto t = musical_tick(100, 200, 0., 1.);
1 ✔
197
  REQUIRE(dates(t.get_quantification_dates(0)) == date_list{{100, 0}});
3 ✔
198
  REQUIRE(dates(t.get_quantification_dates(-1)) == date_list{{100, 0}});
3 ✔
199
}
1 ✔
200

201
TEST_CASE("quantification_dates_no_musical_info", "quantification_dates")
1 ✔
202
{
203
  // Without a musical position there is nothing to quantize against: the tick
204
  // itself is the point. Several nodes rely on this to step once per tick.
205
  auto t = musical_tick(100, 200, 0., 0.);
1 ✔
206
  REQUIRE(dates(t.get_quantification_dates(16)) == date_list{{100, 0}});
3 ✔
207
}
1 ✔
208

209
TEST_CASE("quantification_dates_several_per_tick", "quantification_dates")
1 ✔
210
{
211
  // The whole point of the multi-date version: one tick worth a quarter note
212
  // holds four sixteenths, and none of them may be dropped.
213
  auto t = musical_tick(0, 1000, 0., 1.);
1 ✔
214

215
  const auto expected = date_list{{0, 0}, {250, 1}, {500, 2}, {750, 3}};
2 ✔
216
  REQUIRE(dates(t.get_quantification_dates(16)) == expected);
1 ✔
217
}
1 ✔
218

219
TEST_CASE("quantification_dates_interior_point", "quantification_dates")
1 ✔
220
{
221
  auto t = musical_tick(0, 1000, 0.5, 1.5);
1 ✔
222
  const auto res = t.get_quantification_dates(4);
1 ✔
223

224
  REQUIRE(dates(res) == date_list{{500, 1}});
3 ✔
225
  // and it agrees with the single-date version
226
  auto single = t.get_quantification_date(4);
1 ✔
227
  REQUIRE(single.has_value());
1 ✔
228
  REQUIRE(*single == res[0].date);
1 ✔
229
}
1 ✔
230

231
TEST_CASE("quantification_dates_on_the_start_of_the_tick", "quantification_dates")
1 ✔
232
{
233
  auto t = musical_tick(400, 1000, 1., 1.5);
1 ✔
234
  const auto res = t.get_quantification_dates(4);
1 ✔
235

236
  REQUIRE(dates(res) == date_list{{400, 1}});
3 ✔
237

238
  auto single = t.get_quantification_date(4);
1 ✔
239
  REQUIRE(single.has_value());
1 ✔
240
  REQUIRE(*single == res[0].date);
1 ✔
241
}
1 ✔
242

243
TEST_CASE("quantification_dates_on_the_end_of_the_tick", "quantification_dates")
1 ✔
244
{
245
  // A point falling exactly on the end of a tick belongs to the next one,
246
  // otherwise it would fire twice.
247
  auto t = musical_tick(0, 1000, 0.5, 1.);
1 ✔
248
  REQUIRE(t.get_quantification_dates(4).empty());
1 ✔
249
  REQUIRE(!t.get_quantification_date(4).has_value());
1 ✔
250
}
1 ✔
251

252
TEST_CASE("quantification_dates_bars", "quantification_dates")
1 ✔
253
{
254
  // rate <= 1 counts bars: 1 is every bar, 0.5 every two bars.
255
  auto t = musical_tick(0, 1000, 0., 8.);
1 ✔
256

257
  REQUIRE(dates(t.get_quantification_dates(1)) == date_list{{0, 0}, {500, 1}});
3 ✔
258
  REQUIRE(dates(t.get_quantification_dates(0.5)) == date_list{{0, 0}});
3 ✔
259
}
1 ✔
260

261
TEST_CASE("quantification_dates_odd_signature", "quantification_dates")
1 ✔
262
{
263
  // 7/8: a bar is 3.5 quarters.
264
  auto t = musical_tick(0, 1000, 0., 7., 7, 8);
1 ✔
265
  REQUIRE(dates(t.get_quantification_dates(1)) == date_list{{0, 0}, {500, 1}});
3 ✔
266
}
1 ✔
267

268
TEST_CASE("quantification_dates_are_ordered_and_inside_the_tick", "quantification_dates")
1 ✔
269
{
270
  for(double rate : {1., 2., 4., 8., 16., 32.})
7 ✔
271
  {
272
    auto t = musical_tick(0, 4096, 0.3, 5.7);
6 ✔
273
    const auto res = t.get_quantification_dates(rate);
6 ✔
274

275
    INFO("rate " << rate);
6 ✔
276
    int64_t previous = -1;
6 ✔
277
    for(const auto& q : res)
178 ✔
278
    {
279
      CHECK(q.date.impl >= t.prev_date.impl);
83 ✔
280
      CHECK(q.date.impl < t.date.impl);
83 ✔
281
      CHECK(q.date.impl >= previous);
83 ✔
282
      previous = q.date.impl;
83 ✔
283
    }
284
  }
6 ✔
285
}
1 ✔
286

287
TEST_CASE("musical_to_frame_grid_point_is_not_one_sample_early", "musical_to_frame")
1 ✔
288
{
289
  // 1 kHz, 120 BPM: an eighth note is 250 frames. The positions come out of
290
  // divisions that round them a few ulps below the grid point.
291
  CHECK(ossia::musical_to_frame(0.5, 0.384, 0.512, 64) == 58);
1 ✔
292
  CHECK(ossia::musical_to_frame(0.5, 0., 0.666, 333) == 250);
1 ✔
293
  CHECK(ossia::musical_to_frame(1.5, 1.4000000000000001, 1.6, 100) == 50);
1 ✔
294

295
  // Engine-style ticks: every grid point that falls exactly on a sample lands on it.
296
  for(double rate : {44100., 48000., 96000.})
4 ✔
297
    for(double tempo : {97.3, 120., 133.7})
12 ✔
298
      for(int buffer : {1, 7, 64, 333, 512})
54 ✔
299
      {
300
        const double frames_per_quarter = rate * 60. / tempo;
45 ✔
301
        for(int64_t t = 0; t < 500; t++)
22,545 ✔
302
        {
303
          const double a = t * buffer / frames_per_quarter;
22,500 ✔
304
          const double b = (t + 1) * buffer / frames_per_quarter;
22,500 ✔
305
          for(auto k = int64_t(std::ceil(a / 0.5)); k * 0.5 < b; k++)
22,817 ✔
306
          {
307
            const double exact = k * 0.5 * frames_per_quarter - double(t * buffer);
317 ✔
308
            const double nearest = std::round(exact);
317 ✔
309
            if(std::abs(exact - nearest) > 1e-6 || nearest < 0 || nearest >= buffer)
317 ✔
310
              continue;
179 ✔
311
            INFO(rate << " " << tempo << " " << buffer << " " << t << " " << k);
138 ✔
312
            CHECK(ossia::musical_to_frame(k * 0.5, a, b, buffer) == int64_t(nearest));
138 ✔
313
          }
138 ✔
314
        }
315
      }
316
}
1 ✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc