def test_particle_pool(self): """gen.ParticlePool""" min_f = 123.45 min_f_log = splat.lin2dB(min_f) max_f = 678.9 max_f_log = splat.lin2dB(max_f) min_len = 0.1 max_len = 0.3 envelope = splat.interpol.spline([(0.5, 0.0), (1.3, 1.0), (2.1, 0.0)]) n_slices = 20 density = 200 count = 196 half_count = 103 pool = splat.gen.ParticlePool(min_f_log, max_f_log, min_len, max_len, envelope, n_slices, density) self.assertEqual(pool.start, envelope.start, "Incorrect pool start time") self.assertEqual(pool.end, envelope.end, "Incorrect pool end time") self.assertEqual( pool.count(), count, # plain magic "Unexpected number of particles: {}".format(pool.count())) for p in pool.iterate(share=0.5): self.assertFalse((p.length < min_len) or (p.length > max_len), "Invalid particle length") self.assertFalse( (p.start < envelope.start) or (p.start > envelope.end), "Invalid particle start/end times") self.assertFalse((p.freq < min_f) or (p.freq > max_f), "Invalid particle frequency") self.assertFalse( abs(pool.count() - half_count) > (count / 35.0), "Invalid number of particles left: {}".format(pool.count()))
def run_resample_test(source, duration, ratio, freq, rate, thr): frag1 = splat.data.Fragment(duration=duration, channels=1) source(frag1, 1.0, freq) for ratio_value in (ratio, lambda x: ratio): frag2 = frag1.dup() frag2.resample(ratio=ratio_value, rate=rate) new_length = int(len(frag1) * ratio * rate / frag1.rate) if isinstance(ratio_value, float): self.assertEqual(len(frag2), new_length, "Incorrect resampled fragment length") new_duration = float(new_length) / frag2.rate self.assertAlmostEqual(frag2.duration, new_duration, self._places, "Incorrect resampled fragment duration") else: new_length = min(len(frag1), new_length) delta = abs(len(frag2) - new_length) self.assertLessEqual(delta, 1, "Incorrect signal resampled fragment length") ref = splat.data.Fragment(length=len(frag2), channels=1, rate=rate) source(ref, 1.0, (freq / ratio)) delta = splat.tools.compare.frag_delta(ref, frag2) err = splat.lin2dB(delta.get_peak()[0]['peak']) self.assertLess(err, thr, "Interpolation error: {:.1f} dB".format(err))
def file_peak_delta_dB(f1_path, f2_path, save_path=None): f1 = splat.data.Fragment.open(f1_path) f2 = splat.data.Fragment.open(f2_path) delta = frag_delta(f1, f2) if save_path: delta.save(save_path, normalize=False) return splat.lin2dB(delta.get_peak()[0]['peak'])
def test_particle(self): """gen.Particle""" start = 1.2 end = 3.4 f = 1234.56 p = splat.gen.Particle(start, end, splat.lin2dB(f)) self.assertEqual(p.start, start, "Incorrect particle start time") self.assertEqual(p.end, end, "Incorrect particle end time") self.assertAlmostEqual(p.freq, f, 6, msg="Frequency conversion error: {} instead of {}".format(f, p.freq))
def test_particle(self): """gen.Particle""" start = 1.2 end = 3.4 f = 1234.56 p = splat.gen.Particle(start, end, splat.lin2dB(f)) self.assertEqual(p.start, start, "Incorrect particle start time") self.assertEqual(p.end, end, "Incorrect particle end time") self.assertAlmostEqual( p.freq, f, 6, msg="Frequency conversion error: {} instead of {}".format( f, p.freq))
def main(argv): parser = argparse.ArgumentParser( "Compute the difference between sound files") parser.add_argument('f1', help="path to first sound file") parser.add_argument('f2', help="path to second sound file") parser.add_argument('--save', help="path to save the difference") args = parser.parse_args(argv[1:]) f1 = splat.data.Fragment.open(args.f1) f2 = splat.data.Fragment.open(args.f2) delta = frag_diff(f1, f2) print("Peak error: {:.3f} dB".format( splat.lin2dB(delta.get_peak()[0]['peak']))) if args.save: delta.save(args.save, normalize=False) return True
def run_tests(freq=123.45, duration=30.0, phase=23.456, pts=None, overtones=None, verbose=False): if pts is None: pts = [0.0, 0.2, 0.234, 0.456, 0.45602, 0.7124, 0.89, 0.90001] if overtones is None: overtones = [(1.0, 0.0, 0.45), (2.58, 12.345, 0.45), (200.0, 0.0, 1.0)] cases = [] # ------------------------------------------------------------------------- frag = splat.data.Fragment(channels=1) gen = splat.gen.SineGenerator(frag=frag) gen.run(0.0, duration, freq, phase) frag.save('sine-{}.wav'.format(splat.SAMPLE_WIDTH), normalize=False) cases.append('sine') if verbose: print('sine') for t in pts: t = duration * t n = frag.s2n(t) t = float(n) / frag.rate st = 2 * cmath.pi * freq * (t + phase) y1 = frag[n][0] y2 = math.sin(st) delta = abs(y2 - y1) if delta != 0.0: delta_dB = "{:.3f}".format(splat.lin2dB(delta)) else: delta_dB = 'infinity' if verbose: print(t, y1, y2, delta_dB) # ------------------------------------------------------------------------- frag = splat.data.Fragment(channels=1) gen = splat.gen.OvertonesGenerator(frag=frag) gen.overtones = overtones gen.run(0.0, duration, freq) frag.save('overtones-{}.wav'.format(splat.SAMPLE_WIDTH), normalize=False) cases.append('overtones') max_ratio = frag.rate / 2.0 / freq ot_clipped = [] for ot in gen.overtones: if ot[0] < max_ratio: ot_clipped.append(ot) if verbose: print('overtones') for t in pts: t = duration * t n = frag.s2n(t) y1 = frag[n][0] y2 = sum(a * math.sin(2 * cmath.pi * freq * r * (t + ph)) for r, ph, a in ot_clipped) delta = abs(y2 - y1) if delta != 0.0: delta_dB = "{:.3f}".format(splat.lin2dB(delta)) else: delta_dB = 'infinity' if verbose: print(t, y1, y2, delta_dB) # ------------------------------------------------------------------------- duration = 1.0 sig = splat.data.Fragment(channels=1) splat.gen.TriangleGenerator(frag=sig).run(0.0, duration, 12.0, levels=0.5) sig.offset(0.5) mod = splat.data.Fragment(channels=1) splat.gen.TriangleGenerator(frag=mod).run(0.0, duration, 4.0, levels=0.002) mod.offset(0.5) frag = splat.data.Fragment() splat.gen.SineGenerator(frag=frag).run(0.0, duration, 456.0, levels=sig, phase=lambda x: math.sin(x)) frag.save('sine-signal-{}.wav'.format(splat.SAMPLE_WIDTH), normalize=False) cases.append('sine-signal') frag = splat.data.Fragment() gen = splat.gen.OvertonesGenerator(frag=frag) gen.overtones = overtones gen.run(0.0, duration, 456.0, levels=sig) frag.save('overtones-mixed1-{}.wav'.format(splat.SAMPLE_WIDTH), normalize=False) cases.append('overtones-mixed1') frag = splat.data.Fragment() gen = splat.gen.OvertonesGenerator(frag=frag) gen.overtones = overtones gen.run(0.0, duration, 456.0, levels=sig, phase=mod) frag.save('overtones-mixed2-{}.wav'.format(splat.SAMPLE_WIDTH), normalize=False) cases.append('overtones-mixed2') sig2 = splat.data.Fragment(channels=1) splat.gen.TriangleGenerator(frag=sig2).run(0.0, duration, 1.8, levels=0.1) sig2.offset(-sig2.get_peak()[0]['min']) overtones.append((0.54, 0.0, sig2)) frag = splat.data.Fragment() gen = splat.gen.OvertonesGenerator(frag=frag) gen.overtones = overtones gen.run(0.0, duration, 456.0, levels=sig, phase=mod) frag.save('overtones-signal-{}.wav'.format(splat.SAMPLE_WIDTH), normalize=False) cases.append('overtones-signal') frag = splat.data.Fragment() gen = splat.gen.SineGenerator(frag=frag) gen.run(0.0, 5.678, 1234.56, levels=dB(-3)) ratio = 1.987 new_len = int(len(frag) * ratio) rem = new_len % 4 if rem: new_len -= rem else: new_len -= 4 frag.resample(ratio=ratio) frag.resize(length=new_len) frag.save('resample-float-{}.wav'.format(splat.SAMPLE_WIDTH)) cases.append('resample-float') frag = splat.data.Fragment() gen = splat.gen.SineGenerator(frag=frag) gen.run(0.0, 5.678, 1234.56, levels=dB(-3)) ratio = 1.987 frag.resample(ratio=lambda x: ratio) frag.save('resample-signal-{}.wav'.format(splat.SAMPLE_WIDTH)) cases.append('resample-signal') return cases