1 /*  Copyright 2015 Sami Boukortt
2 
3     This program is free software: you can redistribute it and/or modify
4     it under the terms of the GNU General Public License as published by
5     the Free Software Foundation, either version 3 of the License, or
6     (at your option) any later version.
7 
8     This program is distributed in the hope that it will be useful,
9     but WITHOUT ANY WARRANTY; without even the implied warranty of
10     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11     GNU General Public License for more details.
12 
13     You should have received a copy of the GNU General Public License
14     along with this program.  If not, see <http://www.gnu.org/licenses/>.
15 */
16 
17 #include "intersect.h"
18 
19 #include <fftw3.h>
20 #include <string.h>
21 #include "types.h"
22 #include "util.h"
23 
amplitude_squared(const float c[2])24 static float amplitude_squared(const float c[2]) {
25 	return c[0] * c[0] + c[1] * c[1];
26 }
27 
run(LV2_Handle handle,uint32_t sample_count,Effect effect)28 static void run(LV2_Handle handle, uint32_t sample_count, Effect effect) {
29 	Intersect *intersect = handle;
30 	float *cursor_input [2] = {intersect->input [LEFT], intersect->input [RIGHT]},
31 	      *cursor_output[3] = {intersect->output[LEFT], intersect->output[RIGHT], intersect->output[CENTER]};
32 
33 	while (sample_count > 0) {
34 		const uint32_t block_size = min(sample_count, intersect->fft_jump_size - intersect->deviation);
35 		uint32_t i;
36 
37 		for (i = 0; i < block_size; ++i) {
38 			cursor_output[0][i] = intersect->output_buffer[CENTER][i + intersect->deviation] * intersect->normalization_factor;
39 		}
40 
41 		switch (effect) {
42 			case INTERSECT: break;
43 
44 			case UPMIX:
45 				memcpy(cursor_output[CENTER], cursor_output[0], block_size * sizeof(float));
46 
47 				/* fallthrough */
48 			case SYMMETRIC_DIFFERENCE: {
49 				int c_;
50 				for (c_ = 0; c_ < 2; ++c_) {
51 					const int c = 1 - c_;
52 					for (i = 0; i < block_size; ++i) {
53 						cursor_output[c][i] = intersect->output_buffer[c][i + intersect->deviation] - cursor_output[0][i];
54 					}
55 				}
56 				break;
57 			}
58 		}
59 
60 		for (i = 0; i < 2; ++i) {
61 			memcpy(
62 				intersect->input_buffer[i] + intersect->fft_size - intersect->fft_jump_size + intersect->deviation,
63 				cursor_input[i],
64 				block_size * sizeof(float)
65 			);
66 		}
67 
68 		intersect->deviation += block_size;
69 
70 		if (intersect->deviation == intersect->fft_jump_size) {
71 			memmove(intersect->output_buffer[CENTER], intersect->output_buffer[CENTER] + intersect->fft_jump_size, (intersect->fft_size - intersect->fft_jump_size) * sizeof(float));
72 			memset(intersect->output_buffer[CENTER] + (intersect->fft_size - intersect->fft_jump_size), 0, intersect->fft_jump_size * sizeof(float));
73 
74 			fftwf_execute(intersect->plan_r2c);
75 
76 			for (i = 0; i < intersect->fft_size / 2 + 1; ++i) {
77 				const float * const left   = intersect->transformed[LEFT] [i],
78 				            * const right  = intersect->transformed[RIGHT][i],
79 				            * const winner = (amplitude_squared(left) < amplitude_squared(right)) ? left : right;
80 				memcpy(intersect->pre_output[i], winner, 2 * sizeof(float));
81 			}
82 
83 			fftwf_execute(intersect->plan_c2r);
84 
85 			for (i = 0; i < intersect->fft_size; ++i) {
86 				intersect->output_buffer[CENTER][i] += intersect->ifft_result[i];
87 			}
88 			for (i = 0; i < 2; ++i) {
89 				memcpy(intersect->output_buffer[i], intersect->input_buffer[i], intersect->fft_jump_size * sizeof(float));
90 				memmove(intersect->input_buffer[i], intersect->input_buffer[i] + intersect->fft_jump_size, (intersect->fft_size - intersect->fft_jump_size) * sizeof(float));
91 			}
92 
93 			intersect->deviation = 0;
94 		}
95 
96 		cursor_input[LEFT]    += block_size;
97 		cursor_input[RIGHT]   += block_size;
98 		cursor_output[LEFT]   += block_size;
99 		cursor_output[RIGHT]  += block_size;
100 		cursor_output[CENTER] += block_size;
101 		sample_count          -= block_size;
102 	}
103 
104 	if (intersect->latency != NULL) {
105 		*intersect->latency = intersect->fft_size;
106 	}
107 }
108 
intersect_run(LV2_Handle handle,uint32_t sample_count)109 void intersect_run(LV2_Handle handle, uint32_t sample_count) {
110 	run(handle, sample_count, INTERSECT);
111 }
112 
symmetric_difference_run(LV2_Handle handle,uint32_t sample_count)113 void symmetric_difference_run(LV2_Handle handle, uint32_t sample_count) {
114 	run(handle, sample_count, SYMMETRIC_DIFFERENCE);
115 }
116 
upmix_run(LV2_Handle handle,uint32_t sample_count)117 void upmix_run(LV2_Handle handle, uint32_t sample_count) {
118 	run(handle, sample_count, UPMIX);
119 }
120