• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***
2   This file is part of PulseAudio.
3 
4   PulseAudio is free software; you can redistribute it and/or modify
5   it under the terms of the GNU Lesser General Public License as published
6   by the Free Software Foundation; either version 2.1 of the License,
7   or (at your option) any later version.
8 
9   PulseAudio is distributed in the hope that it will be useful, but
10   WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12   General Public License for more details.
13 
14   You should have received a copy of the GNU Lesser General Public License
15   along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
16 ***/
17 
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
21 
22 #include <check.h>
23 
24 #include <pulse/pulseaudio.h>
25 #include <pulse/sample.h>
26 #include <pulsecore/memblock.h>
27 
28 #include <pulsecore/filter/lfe-filter.h>
29 
30 struct lfe_filter_test {
31     pa_lfe_filter_t *lf;
32     pa_mempool *pool;
33     pa_sample_spec *ss;
34 };
35 
36 static uint8_t *ori_sample_ptr;
37 
38 #define ONE_BLOCK_SAMPLES 4096
39 #define TOTAL_SAMPLES 8192
40 #define TOLERANT_VARIATION 1
41 
save_data_block(struct lfe_filter_test * lft,void * d,pa_memblock * blk)42 static void save_data_block(struct lfe_filter_test *lft, void *d, pa_memblock *blk) {
43     uint8_t *dst = d, *src;
44     size_t blk_size = pa_frame_size(lft->ss) * ONE_BLOCK_SAMPLES;
45 
46     src = pa_memblock_acquire(blk);
47     memcpy(dst, src, blk_size);
48     pa_memblock_release(blk);
49 }
50 
generate_data_block(struct lfe_filter_test * lft,int start)51 static pa_memblock* generate_data_block(struct lfe_filter_test *lft, int start) {
52     pa_memblock *r;
53     uint8_t *d, *s = ori_sample_ptr;
54     size_t blk_size = pa_frame_size(lft->ss) * ONE_BLOCK_SAMPLES;
55 
56     pa_assert_se(r = pa_memblock_new(lft->pool, blk_size));
57     d = pa_memblock_acquire(r);
58     memcpy(d, s + start,  blk_size);
59     pa_memblock_release(r);
60 
61     return r;
62 }
63 
compare_data_block(struct lfe_filter_test * lft,void * a,void * b)64 static int compare_data_block(struct lfe_filter_test *lft, void *a, void *b) {
65     int ret = 0;
66     uint32_t i;
67     uint16_t *r = a, *u = b;
68 
69     pa_assert(lft->ss->format == PA_SAMPLE_S16NE);
70 
71     for (i = 0; i < ONE_BLOCK_SAMPLES; i++) {
72         if (abs(*r++ - *u++) > TOLERANT_VARIATION) {
73             pa_log_error("lfe-filter-test: test failed, the output data in the position 0x%x of a block does not equal!", i);
74             ret = -1;
75             break;
76         }
77     }
78     return ret;
79 }
80 
81 /* in this test case, we pass two blocks of sample data to lfe-filter, each
82    block contains 4096 samples, and don't let rewind_samples exceed TOTAL_SAMPLES */
lfe_filter_rewind_test(struct lfe_filter_test * lft,int rewind_samples)83 static int lfe_filter_rewind_test(struct lfe_filter_test *lft, int rewind_samples)
84 {
85     int ret = -1, pos, i;
86     pa_memchunk mc;
87     uint8_t *outptr;
88     uint32_t fz = pa_frame_size(lft->ss);
89 
90     if (rewind_samples > TOTAL_SAMPLES || rewind_samples < TOTAL_SAMPLES - ONE_BLOCK_SAMPLES) {
91         pa_log_error("lfe-filter-test: Please keep %d samples < rewind_samples < %d samples", TOTAL_SAMPLES - ONE_BLOCK_SAMPLES, TOTAL_SAMPLES);
92         return ret;
93     }
94 
95     outptr = pa_xmalloc(fz * TOTAL_SAMPLES);
96 
97     /* let lfe-filter process all samples first, and save the processed data to the temp buffer,
98        then rewind back to some position, reprocess some samples and compare the output data with
99        the processed data saved before. */
100     for (i = 0; i < TOTAL_SAMPLES / ONE_BLOCK_SAMPLES; i++) {
101         mc.memblock = generate_data_block(lft, i * ONE_BLOCK_SAMPLES * fz);
102         mc.length = pa_memblock_get_length(mc.memblock);
103         mc.index = 0;
104         pa_lfe_filter_process(lft->lf, &mc);
105         save_data_block(lft, outptr + i * ONE_BLOCK_SAMPLES * fz, mc.memblock);
106         pa_memblock_unref(mc.memblock);
107     }
108 
109     pa_lfe_filter_rewind(lft->lf, rewind_samples * fz);
110     pos = (TOTAL_SAMPLES - rewind_samples) * fz;
111     mc.memblock = generate_data_block(lft, pos);
112     mc.length = pa_memblock_get_length(mc.memblock);
113     mc.index = 0;
114     pa_lfe_filter_process(lft->lf, &mc);
115     ret = compare_data_block(lft, outptr + pos, pa_memblock_acquire(mc.memblock));
116     pa_memblock_release(mc.memblock);
117     pa_memblock_unref(mc.memblock);
118 
119     pa_xfree(outptr);
120 
121     return ret;
122 }
123 
START_TEST(lfe_filter_test)124 START_TEST (lfe_filter_test) {
125     pa_sample_spec a;
126     int ret = -1;
127     unsigned i, crossover_freq = 120;
128     pa_channel_map chmapmono = {1, {PA_CHANNEL_POSITION_LFE}};
129     struct lfe_filter_test lft;
130     short *tmp_ptr;
131 
132     pa_log_set_level(PA_LOG_DEBUG);
133 
134     a.channels = 1;
135     a.rate = 44100;
136     a.format = PA_SAMPLE_S16NE;
137 
138     lft.ss = &a;
139     pa_assert_se(lft.pool = pa_mempool_new(PA_MEM_TYPE_PRIVATE, 0, true));
140 
141     /* We prepare pseudo-random input audio samples for lfe-filter rewind testing*/
142     ori_sample_ptr = pa_xmalloc(pa_frame_size(lft.ss) * TOTAL_SAMPLES);
143     tmp_ptr = (short *) ori_sample_ptr;
144     for (i = 0; i < pa_frame_size(lft.ss) * TOTAL_SAMPLES / sizeof(short); i++)
145         *tmp_ptr++ = random();
146 
147     /* we create a lfe-filter with cutoff frequency 120Hz and max rewind time 10 seconds */
148     pa_assert_se(lft.lf = pa_lfe_filter_new(&a, &chmapmono, crossover_freq, a.rate * 10));
149     /* rewind to a block boundary */
150     ret = lfe_filter_rewind_test(&lft, ONE_BLOCK_SAMPLES);
151     if (ret)
152         pa_log_error("lfe-filer-test: rewind to block boundary test failed!!!");
153     pa_lfe_filter_free(lft.lf);
154 
155     /* we create a lfe-filter with cutoff frequency 120Hz and max rewind time 10 seconds */
156     pa_assert_se(lft.lf = pa_lfe_filter_new(&a, &chmapmono, crossover_freq, a.rate * 10));
157     /* rewind to the middle position of a block */
158     ret = lfe_filter_rewind_test(&lft, ONE_BLOCK_SAMPLES + ONE_BLOCK_SAMPLES / 2);
159     if (ret)
160         pa_log_error("lfe-filer-test: rewind to middle of block test failed!!!");
161 
162     pa_xfree(ori_sample_ptr);
163 
164     pa_lfe_filter_free(lft.lf);
165 
166     pa_mempool_unref(lft.pool);
167 
168     if (!ret)
169         pa_log_debug("lfe-filter-test: tests for both rewind to block boundary and rewind to middle position of a block passed!");
170 
171     fail_unless(ret == 0);
172 }
173 END_TEST
174 
main(int argc,char * argv[])175 int main(int argc, char *argv[]) {
176     int failed = 0;
177     Suite *s;
178     TCase *tc;
179     SRunner *sr;
180 
181     if (!getenv("MAKE_CHECK"))
182         pa_log_set_level(PA_LOG_DEBUG);
183 
184     s = suite_create("lfe-filter");
185     tc = tcase_create("lfe-filter");
186     tcase_add_test(tc, lfe_filter_test);
187     tcase_set_timeout(tc, 10);
188     suite_add_tcase(s, tc);
189 
190     sr = srunner_create(s);
191     srunner_run_all(sr, CK_NORMAL);
192     failed = srunner_ntests_failed(sr);
193     srunner_free(sr);
194 
195     return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
196 }
197