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