annotate test/test_process.py @ 70:ffdeb8808fc1

Let's favour consistent shape in output, and return the output identifier always
author Chris Cannam
date Wed, 14 Jan 2015 17:19:04 +0000
parents b34d3b58da98
children cb0380c92c42
rev   line source
Chris@61 1
Chris@61 2 import vamp
Chris@61 3 import numpy as np
Chris@61 4
Chris@61 5 testPluginKey = "vamp-test-plugin:vamp-test-plugin"
Chris@66 6 testPluginKeyFreq = "vamp-test-plugin:vamp-test-plugin-freq"
Chris@61 7
Chris@61 8 rate = 44100
Chris@61 9
Chris@68 10 # Throughout this file we have the assumption that the plugin gets run with a
Chris@68 11 # blocksize of 1024, and with a step of 1024 for the time-domain version or 512
Chris@68 12 # for the frequency-domain one. That is certainly expected to be the norm for a
Chris@68 13 # plugin like this that declares no preference, and the Python Vamp module is
Chris@68 14 # expected to follow the norm
Chris@66 15
Chris@68 16 blocksize = 1024
Chris@68 17
Chris@68 18 def input_data(n):
Chris@68 19 # start at 1, not 0 so that all elts are non-zero
Chris@68 20 return np.arange(n) + 1
Chris@68 21
Chris@68 22 def test_process_n():
Chris@68 23 buf = input_data(blocksize)
Chris@68 24 results = list(vamp.process(buf, rate, testPluginKey, {}, [ "input-summary" ]))
Chris@68 25 assert len(results) == 1
Chris@68 26
Chris@68 27 def test_process_freq_n():
Chris@68 28 buf = input_data(blocksize)
Chris@68 29 results = list(vamp.process(buf, rate, testPluginKeyFreq, {}, [ "input-summary" ]))
Chris@68 30 assert len(results) == 2 # one complete block starting at zero, one half-full
Chris@68 31
Chris@68 32 def test_process_summary_param():
Chris@68 33 buf = input_data(blocksize * 10)
Chris@68 34 results = list(vamp.process(buf, rate, testPluginKey, { "produce_output": 0 }, [ "input-summary" ]))
Chris@68 35 assert len(results) == 0
Chris@68 36
Chris@68 37 def test_process_summary_param_bool():
Chris@68 38 buf = input_data(blocksize * 10)
Chris@68 39 results = list(vamp.process(buf, rate, testPluginKey, { "produce_output": False }, [ "input-summary" ]))
Chris@68 40 assert len(results) == 0
Chris@68 41
Chris@68 42 def test_process_summary():
Chris@68 43 buf = input_data(blocksize * 10)
Chris@68 44 results = list(vamp.process(buf, rate, testPluginKey, {}, [ "input-summary" ]))
Chris@68 45 assert len(results) == 10
Chris@68 46 for i in range(len(results)):
Chris@69 47 #
Chris@68 48 # each feature has a single value, equal to the number of non-zero elts
Chris@68 49 # in the input block (which is all of them, i.e. the blocksize) plus
Chris@68 50 # the first elt (which is i * blockSize + 1)
Chris@69 51 #
Chris@68 52 expected = blocksize + i * blocksize + 1
Chris@70 53 actual = results[i]["input-summary"]["values"][0]
Chris@68 54 assert actual == expected
Chris@68 55
Chris@68 56 def test_process_freq_summary():
Chris@68 57 buf = input_data(blocksize * 10)
Chris@68 58 results = list(vamp.process(buf, rate, testPluginKeyFreq, {}, [ "input-summary" ]))
Chris@68 59 assert len(results) == 20
Chris@68 60 for i in range(len(results)):
Chris@68 61 #
Chris@68 62 # sort of as above, but much much subtler:
Chris@68 63 #
Chris@68 64 # * the input block is converted to frequency domain but then converted
Chris@68 65 # back within the plugin, so the values being reported are time-domain
Chris@68 66 # ones but with windowing and FFT shift
Chris@68 67 #
Chris@68 68 # * the effect of FFT shift is that the first element in the
Chris@68 69 # re-converted frame is actually the one that was at the start of the
Chris@68 70 # second half of the original frame
Chris@68 71 #
Chris@68 72 # * and the last block is only half-full, so the "first" elt in that
Chris@68 73 # one, which actually comes from just after the middle of the block,
Chris@68 74 # will be zero
Chris@68 75 #
Chris@68 76 # * windowing does not affect the value of the first elt, because
Chris@68 77 # (before fft shift) it came from the peak of the window shape where
Chris@68 78 # the window value is 1
Chris@68 79 #
Chris@68 80 # * but windowing does affect the number of non-zero elts, because the
Chris@68 81 # asymmetric window used has one value very close to zero in it
Chris@68 82 #
Chris@68 83 # * the step size (the increment in input value from one block to the
Chris@68 84 # next) is only half the block size
Chris@68 85 #
Chris@68 86 expected = i * (blocksize/2) + blocksize/2 + 1 # "first" elt
Chris@68 87 if (i == len(results)-1):
Chris@68 88 expected = 0
Chris@68 89 expected = expected + blocksize - 1 # non-zero elts
Chris@70 90 actual = results[i]["input-summary"]["values"][0]
Chris@68 91 eps = 1e-6
Chris@68 92 assert abs(actual - expected) < eps
Chris@68 93
Chris@69 94 def test_process_timestamps():
Chris@69 95 buf = input_data(blocksize * 10)
Chris@69 96 results = list(vamp.process(buf, rate, testPluginKey, {}, [ "input-timestamp" ]))
Chris@69 97 assert len(results) == 10
Chris@69 98 for i in range(len(results)):
Chris@69 99 # The timestamp should be the frame number of the first frame in the
Chris@69 100 # input buffer
Chris@69 101 expected = i * blocksize
Chris@70 102 actual = results[i]["input-timestamp"]["values"][0]
Chris@69 103 assert actual == expected
Chris@69 104
Chris@69 105 def test_process_freq_timestamps():
Chris@69 106 buf = input_data(blocksize * 10)
Chris@69 107 results = list(vamp.process(buf, rate, testPluginKeyFreq, {}, [ "input-timestamp" ]))
Chris@69 108 assert len(results) == 20
Chris@69 109 for i in range(len(results)):
Chris@69 110 # The timestamp should be the frame number of the frame just beyond
Chris@69 111 # half-way through the input buffer
Chris@69 112 expected = i * (blocksize/2) + blocksize/2
Chris@70 113 actual = results[i]["input-timestamp"]["values"][0]
Chris@69 114 print("actual = " + str(actual) + ", expected = " + str(expected))
Chris@69 115 assert actual == expected