1 /**
2 * Impulse Response Processor model implementation
3 * Low Latency Version
4 *
5 * Copyright (C) 2006-2018 Teru Kamogashira
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21
22 #include "freeverb/irmodel2zl.hpp"
23 #include "freeverb/fv3_type_float.h"
24 #include "freeverb/fv3_ns_start.h"
25
26 // irmodel2zlm
27
FV3_(irmodel2zlm)28 FV3_(irmodel2zlm)::FV3_(irmodel2zlm)()
29 {
30 ZLstart = 0;
31 }
32
FV3_(irmodel2zlm)33 FV3_(irmodel2zlm)::FV3_(~irmodel2zlm)()
34 {
35 ;
36 }
37
FV3_(irmodel2zlm)38 void FV3_(irmodel2zlm)::loadImpulse(const fv3_float_t * inputL, long size)
39 throw(std::bad_alloc)
40 {
41 if(size <= 0) return;
42 unloadImpulse();
43 try
44 {
45 FV3_(irmodel2m)::loadImpulse(inputL, size);
46 zlFrameSlot.alloc(fragmentSize, 1);
47 zlOnlySlot.alloc(fragmentSize, 1);
48 latency = 0;
49 mute();
50 }
51 catch(std::bad_alloc)
52 {
53 std::fprintf(stderr, "irmodel2zlm::loadImpulse(%ld) bad_alloc\n", size);
54 unloadImpulse();
55 throw;
56 }
57 }
58
FV3_(irmodel2zlm)59 void FV3_(irmodel2zlm)::unloadImpulse()
60 {
61 if(impulseSize == 0) return;
62 FV3_(irmodel2m)::unloadImpulse();
63 zlFrameSlot.free();
64 zlOnlySlot.free();
65 }
66
FV3_(irmodel2zlm)67 void FV3_(irmodel2zlm)::processreplace(fv3_float_t *inputL, long numsamples)
68 {
69 if(numsamples <= 0||fragmentSize <= 0) return;
70 if(numsamples > fragmentSize) // divide into fragmentSize pieces
71 {
72 long div = numsamples/fragmentSize;
73 for(long i = 0;i < div;i ++){ processreplace(inputL+i*fragmentSize, fragmentSize); }
74 processreplace(inputL+div*fragmentSize, numsamples%fragmentSize);
75 return;
76 }
77
78 long cursor = fragmentSize - ZLstart;
79 // numsamples <= fragmentSize
80 // numsamples-cursor <= fragmentSize-cursor = ZLstart <= fragmentSize
81 if(cursor >= numsamples)
82 {
83 processZL(inputL, fifoSlot.L, numsamples);
84 }
85 else
86 {
87 processZL(inputL, fifoSlot.L, cursor);
88 processZL(inputL+cursor, fifoSlot.L+cursor, numsamples-cursor);
89 }
90 std::memcpy(inputL, fifoSlot.L, sizeof(fv3_float_t)*numsamples);
91 }
92
FV3_(irmodel2zlm)93 void FV3_(irmodel2zlm)::processZL(fv3_float_t *inputL, fv3_float_t *outputL, long numsamples)
94 {
95 // numsamples <= fragmentSize - ZLstart
96 if(ZLstart == 0)
97 {
98 zlFrameSlot.mute();
99 reverseSlot.mute(fragmentSize-1, fragmentSize+1);
100 swapSlot.mute();
101 for(long i = 1;i < (long)fragments.size();i ++){ fragments[i]->MULT(blkdelayDL.at(ifftSlot.L, i-1), swapSlot.L); }
102 }
103 zlOnlySlot.mute();
104 std::memcpy(zlFrameSlot.L+ZLstart, inputL, sizeof(fv3_float_t)*numsamples);
105 std::memcpy(zlOnlySlot.L+ZLstart, inputL, sizeof(fv3_float_t)*numsamples);
106
107 fragFFT.R2HC(zlOnlySlot.L, ifftSlot.L);
108 fragments[0]->MULT(ifftSlot.L, swapSlot.L);
109 reverseSlot.mute();
110 fragFFT.HC2R(swapSlot.L, reverseSlot.L);
111
112 for(long i = 0;i < numsamples;i ++){ outputL[i] = (reverseSlot.L+ZLstart)[i] + (restSlot.L+ZLstart)[i]; }
113 ZLstart += numsamples;
114 if(ZLstart == fragmentSize)
115 {
116 fragFFT.R2HC(zlFrameSlot.L, ifftSlot.L);
117 std::memcpy(restSlot.L, reverseSlot.L+fragmentSize, sizeof(fv3_float_t)*(fragmentSize-1));
118 ZLstart = 0;
119 }
120 }
121
FV3_(irmodel2zlm)122 void FV3_(irmodel2zlm)::mute()
123 {
124 FV3_(irmodel2m)::mute();
125 ZLstart = 0;
126 zlFrameSlot.mute();
127 zlOnlySlot.mute();
128 }
129
130 // irmodel2zl
131
FV3_(irmodel2zl)132 FV3_(irmodel2zl)::FV3_(irmodel2zl)()
133 {
134 delete irmL, irmL = NULL;
135 delete irmR, irmR = NULL;
136 try
137 {
138 ir2mL = new FV3_(irmodel2zlm);
139 ir2mR = new FV3_(irmodel2zlm);
140 irmL = ir2mL;
141 irmR = ir2mR;
142 }
143 catch(std::bad_alloc)
144 {
145 delete irmL;
146 delete irmR;
147 throw;
148 }
149 }
150
FV3_(irmodel2zl)151 FV3_(irmodel2zl)::FV3_(~irmodel2zl)()
152 {
153 ;
154 }
155
FV3_(irmodel2zl)156 void FV3_(irmodel2zl)::loadImpulse(const fv3_float_t * inputL, const fv3_float_t * inputR, long size)
157 throw(std::bad_alloc)
158 {
159 if(size <= 0||fragmentSize < FV3_IR_Min_FragmentSize) return;
160 unloadImpulse();
161 try
162 {
163 FV3_(irmodel2)::loadImpulse(inputL, inputR, size);
164 latency = 0;
165 setInitialDelay(getInitialDelay());
166 mute();
167 }
168 catch(std::bad_alloc)
169 {
170 std::fprintf(stderr, "irmodel2zl::loadImpulse(%ld) bad_alloc\n", size);
171 unloadImpulse();
172 throw;
173 }
174 }
175
176 #include "freeverb/fv3_ns_end.h"
177