diff --git a/cmd/tools/modules/testing/common.v b/cmd/tools/modules/testing/common.v index 59729ba1ac..0f239ac176 100644 --- a/cmd/tools/modules/testing/common.v +++ b/cmd/tools/modules/testing/common.v @@ -299,6 +299,7 @@ pub fn new_test_session(_vargs string, will_compile bool) TestSession { skip_files << 'vlib/crypto/ecdsa/example/ensure_compatibility_with_net_openssl_test.v' // requires OpenSSL // Fails compilation with: `/usr/bin/ld: /lib/x86_64-linux-gnu/libpthread.so.0: error adding symbols: DSO missing from command line` skip_files << 'examples/sokol/sounds/simple_sin_tones.v' + skip_files << 'examples/sokol/sounds/simple_sin_tone_using_audio_push.v' } if github_job != 'misc-tooling' { // These examples need .h files that are produced from the supplied .glsl files, diff --git a/examples/sokol/sounds/simple_sin_tone_using_audio_push.v b/examples/sokol/sounds/simple_sin_tone_using_audio_push.v new file mode 100644 index 0000000000..99b7fe5e31 --- /dev/null +++ b/examples/sokol/sounds/simple_sin_tone_using_audio_push.v @@ -0,0 +1,67 @@ +// import log +import math +import time +import sokol.audio + +fn main() { + args := arguments() + freq := args[1] or { '417' }.int() + amplitude := args[2] or { '0.5' }.f32() + dump(freq) + dump(amplitude) + + audio.setup(num_channels: 1) + sample_rate := dump(audio.sample_rate()) + dump(audio.buffer_frames()) + dump(audio.expect()) + + // create an array of frames, filled with the desired pure sine tone: + mut frames := []f32{len: sample_rate * 2} // 2 seconds + for i in 0 .. frames.len { + t := f32(i) / f32(sample_rate) + frames[i] = amplitude * math.sinf(f32(freq) * t * (2 * math.pi)) + } + + // play the sound by continuosly pushing samples from the generated + // array of sound frames, when there is need for more: + mut fpos := 0 + for { + expected_frames := audio.expect() + if expected_frames > 0 { + written_frames := audio.push(unsafe { &frames[fpos] }, expected_frames) + fpos += written_frames + // log.info('> pushing done ... fpos: ${fpos:6} | expected_frames: ${expected_frames:6} | written: ${written:6}') + if fpos > frames.len - 2 * written_frames { + // log.info('> fpos too large: ${fpos}') + fpos = find_loop_position(fpos, frames) + // log.info('> fpos looped back to start: ${fpos}') + } + } + time.sleep(50 * time.millisecond) + } + audio.shutdown() +} + +fn find_loop_position(fpos int, frames []f32) int { + return find_matching_position(frames, fpos, 0.01, 2) or { + find_matching_position(frames, fpos, 0.05, 2) or { + find_matching_position(frames, fpos, 0.1, 2) or { 0 } + } + } +} + +@[direct_array_access] +fn find_matching_position(frames []f32, fpos int, tol f32, d int) ?int { + if fpos - d < 0 || fpos + d >= frames.len { + return none + } + p1, p2, p3 := frames[fpos - d], frames[fpos], frames[fpos + d] + for i in 2 .. fpos / 2 { + np1, np2, np3 := frames[i - d], frames[i], frames[i + d] + if math.tolerance(np1, p1, tol) && math.tolerance(np2, p2, tol) + && math.tolerance(np3, p3, tol) { + return i + } + } + return none +} diff --git a/vlib/math/gamma.v b/vlib/math/gamma.v index 071b1fea31..7edec56d93 100644 --- a/vlib/math/gamma.v +++ b/vlib/math/gamma.v @@ -1,5 +1,13 @@ module math +fn is_neg_int(x f64) bool { + if x < 0 { + _, xf := modf(x) + return xf == 0 + } + return false +} + // gamma function computed by Stirling's formula. // The pair of results must be multiplied together to get the actual answer. // The multiplication is left to the caller so that, if careful, the caller can avoid diff --git a/vlib/math/math.v b/vlib/math/math.v index 46f570ff5f..965be67e07 100644 --- a/vlib/math/math.v +++ b/vlib/math/math.v @@ -166,23 +166,23 @@ pub fn signbit(x f64) bool { return f64_bits(x) & sign_mask != 0 } -// tolerance checks if a and b difference are less than or equal to the tolerance value -pub fn tolerance(a f64, b f64, tol f64) bool { - mut ee := tol - // Multiplying by ee here can underflow denormal values to zero. - // Check a==b so that at least if a and b are small and identical - // we say they match. - if a == b { +// tolerance checks if the difference between `actual` and `expected` numbers, is less than or equal to the tolerance value `tol`. +// Note: the `actual` and `expected` parameters are NOT symmetrical. +// If you compare against a known expected number, put it in the *second* argument, especially if it is 0. +pub fn tolerance(actual f64, expected f64, tol f64) bool { + // Check actual==expected so that at least if they both are small and identical we say they match. + if actual == expected { return true } - mut d := a - b + mut d := actual - expected if d < 0 { d = -d } - // note: b is correct (expected) value, a is actual value. - // make error tolerance a fraction of b, not a. - if b != 0 { - ee = ee * b + mut ee := tol + // make error tolerance a fraction of expected, not actual. + if expected != 0 { + // Multiplying by ee here can underflow denormal values to zero. + ee *= expected if ee < 0 { ee = -ee } @@ -190,14 +190,18 @@ pub fn tolerance(a f64, b f64, tol f64) bool { return d < ee } -// close checks if a and b are within 1e-14 of each other -pub fn close(a f64, b f64) bool { - return tolerance(a, b, 1e-14) +// close checks if `actual` and `expected` are within 1e-14 of each other +// Note: the `actual` and `expected` parameters are NOT symmetrical. +// If you compare against a known expected number, put it in the *second* argument, especially if it is 0. +pub fn close(actual f64, expected f64) bool { + return tolerance(actual, expected, 1e-14) } // veryclose checks if a and b are within 4e-16 of each other -pub fn veryclose(a f64, b f64) bool { - return tolerance(a, b, 4e-16) +// Note: the `actual` and `expected` parameters are NOT symmetrical. +// If you compare against a known expected number, put it in the *second* argument, especially if it is 0. +pub fn veryclose(actual f64, expected f64) bool { + return tolerance(actual, expected, 4e-16) } // alike checks if a and b are equal @@ -221,16 +225,3 @@ pub fn alike(a f64, b f64) bool { } return false } - -fn is_odd_int(x f64) bool { - xi, xf := modf(x) - return xf == 0 && (i64(xi) & 1) == 1 -} - -fn is_neg_int(x f64) bool { - if x < 0 { - _, xf := modf(x) - return xf == 0 - } - return false -} diff --git a/vlib/math/pow.v b/vlib/math/pow.v index e1663c1e80..33cbae72c2 100644 --- a/vlib/math/pow.v +++ b/vlib/math/pow.v @@ -69,6 +69,11 @@ pub fn powi(a i64, b i64) i64 { return v } +fn is_odd_int(x f64) bool { + xi, xf := modf(x) + return xf == 0 && (i64(xi) & 1) == 1 +} + // pow returns the base x, raised to the provided power y. (float64) // // todo(playXE): make this function work on JS backend, probably problem of JS codegen that it does not work.