1 /*
2 * easy.c
3 *
4 * Created on: 18.01.2017
5 * Author: hoene
6 */
7
8 #include <assert.h>
9 #include <stdbool.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include "mysofa.h"
15 #include "mysofa_export.h"
16
17 /**
18 *
19 */
20
21 static struct MYSOFA_EASY *
mysofa_open_default(const char * filename,float samplerate,int * filterlength,int * err,bool applyNorm,float neighbor_angle_step,float neighbor_radius_step)22 mysofa_open_default(const char *filename, float samplerate, int *filterlength,
23 int *err, bool applyNorm, float neighbor_angle_step,
24 float neighbor_radius_step)
25 {
26
27 struct MYSOFA_EASY *easy = malloc(sizeof(struct MYSOFA_EASY));
28
29 if (!easy)
30 {
31 *err = MYSOFA_NO_MEMORY;
32 return NULL;
33 }
34
35 // set all values of struct to their default "0" (to avoid freeing unallocated
36 // values in mysofa_free)
37 *easy = (struct MYSOFA_EASY){0};
38
39 easy->hrtf = mysofa_load(filename, err);
40 if (!easy->hrtf)
41 {
42 mysofa_close(easy);
43 return NULL;
44 }
45
46 *err = mysofa_check(easy->hrtf);
47 if (*err != MYSOFA_OK)
48 {
49 mysofa_close(easy);
50 return NULL;
51 }
52
53 *err = mysofa_resample(easy->hrtf, samplerate);
54 if (*err != MYSOFA_OK)
55 {
56 mysofa_close(easy);
57 return NULL;
58 }
59
60 if (applyNorm)
61 {
62 mysofa_loudness(easy->hrtf);
63 }
64
65 /* does not sound well:
66 mysofa_minphase(easy->hrtf,0.01);
67 */
68
69 mysofa_tocartesian(easy->hrtf);
70
71 if (easy->hrtf->SourcePosition.elements != easy->hrtf->C * easy->hrtf->M)
72 {
73 *err = MYSOFA_INVALID_FORMAT;
74 mysofa_close(easy);
75 return NULL;
76 }
77
78 easy->lookup = mysofa_lookup_init(easy->hrtf);
79 if (easy->lookup == NULL)
80 {
81 *err = MYSOFA_INTERNAL_ERROR;
82 mysofa_close(easy);
83 return NULL;
84 }
85
86 easy->neighborhood = mysofa_neighborhood_init_withstepdefine(
87 easy->hrtf, easy->lookup, neighbor_angle_step, neighbor_radius_step);
88
89 *filterlength = easy->hrtf->N;
90
91 easy->fir = malloc(easy->hrtf->N * easy->hrtf->R * sizeof(float));
92 assert(easy->fir);
93
94 return easy;
95 }
96
mysofa_open(const char * filename,float samplerate,int * filterlength,int * err)97 MYSOFA_EXPORT struct MYSOFA_EASY *mysofa_open(const char *filename,
98 float samplerate,
99 int *filterlength, int *err)
100 {
101 return mysofa_open_default(filename, samplerate, filterlength, err, true,
102 MYSOFA_DEFAULT_NEIGH_STEP_ANGLE,
103 MYSOFA_DEFAULT_NEIGH_STEP_RADIUS);
104 }
105
mysofa_open_no_norm(const char * filename,float samplerate,int * filterlength,int * err)106 MYSOFA_EXPORT struct MYSOFA_EASY *mysofa_open_no_norm(const char *filename,
107 float samplerate,
108 int *filterlength,
109 int *err)
110 {
111 return mysofa_open_default(filename, samplerate, filterlength, err, false,
112 MYSOFA_DEFAULT_NEIGH_STEP_ANGLE,
113 MYSOFA_DEFAULT_NEIGH_STEP_RADIUS);
114 }
115
116 MYSOFA_EXPORT struct MYSOFA_EASY *
mysofa_open_advanced(const char * filename,float samplerate,int * filterlength,int * err,bool norm,float neighbor_angle_step,float neighbor_radius_step)117 mysofa_open_advanced(const char *filename, float samplerate, int *filterlength,
118 int *err, bool norm, float neighbor_angle_step,
119 float neighbor_radius_step)
120 {
121 return mysofa_open_default(filename, samplerate, filterlength, err, norm,
122 neighbor_angle_step, neighbor_radius_step);
123 }
124
mysofa_open_cached(const char * filename,float samplerate,int * filterlength,int * err)125 MYSOFA_EXPORT struct MYSOFA_EASY *mysofa_open_cached(const char *filename,
126 float samplerate,
127 int *filterlength,
128 int *err)
129 {
130 struct MYSOFA_EASY *res = mysofa_cache_lookup(filename, samplerate);
131 if (res)
132 {
133 *filterlength = res->hrtf->N;
134 return res;
135 }
136 res = mysofa_open(filename, samplerate, filterlength, err);
137 if (res)
138 {
139 res = mysofa_cache_store(res, filename, samplerate);
140 }
141 return res;
142 }
143
mysofa_getfilter_short(struct MYSOFA_EASY * easy,float x,float y,float z,short * IRleft,short * IRright,int * delayLeft,int * delayRight)144 MYSOFA_EXPORT void mysofa_getfilter_short(struct MYSOFA_EASY *easy, float x,
145 float y, float z, short *IRleft,
146 short *IRright, int *delayLeft,
147 int *delayRight)
148 {
149 float c[3];
150 float delays[2];
151 float *fl;
152 float *fr;
153 int nearest;
154 int *neighbors;
155 unsigned int i;
156
157 c[0] = x;
158 c[1] = y;
159 c[2] = z;
160 nearest = mysofa_lookup(easy->lookup, c);
161 assert(nearest >= 0);
162 neighbors = mysofa_neighborhood(easy->neighborhood, nearest);
163
164 mysofa_interpolate(easy->hrtf, c, nearest, neighbors, easy->fir, delays);
165
166 *delayLeft = delays[0] * easy->hrtf->DataSamplingRate.values[0];
167 *delayRight = delays[1] * easy->hrtf->DataSamplingRate.values[0];
168
169 fl = easy->fir;
170 fr = easy->fir + easy->hrtf->N;
171 for (i = easy->hrtf->N; i > 0; i--)
172 {
173 *IRleft++ = (short)(*fl++ * 32767.);
174 *IRright++ = (short)(*fr++ * 32767.);
175 }
176 }
177
mysofa_getfilter_float_advanced(struct MYSOFA_EASY * easy,float x,float y,float z,float * IRleft,float * IRright,float * delayLeft,float * delayRight,bool interpolate)178 MYSOFA_EXPORT void mysofa_getfilter_float_advanced(
179 struct MYSOFA_EASY *easy, float x, float y, float z, float *IRleft,
180 float *IRright, float *delayLeft, float *delayRight, bool interpolate)
181 {
182 float c[3];
183 float delays[2];
184 float *fl;
185 float *fr;
186 int nearest;
187 int *neighbors;
188 int i;
189
190 c[0] = x;
191 c[1] = y;
192 c[2] = z;
193 nearest = mysofa_lookup(easy->lookup, c);
194 assert(nearest >= 0);
195 neighbors = mysofa_neighborhood(easy->neighborhood, nearest);
196
197 // bypass interpolate by forcing current cooordinates to nearest's
198 if (!interpolate)
199 {
200 memcpy(c, easy->hrtf->SourcePosition.values + nearest * easy->hrtf->C,
201 sizeof(float) * easy->hrtf->C);
202 }
203
204 float *res =
205 mysofa_interpolate(easy->hrtf, c, nearest, neighbors, easy->fir, delays);
206
207 *delayLeft = delays[0];
208 *delayRight = delays[1];
209
210 fl = res;
211 fr = res + easy->hrtf->N;
212 for (i = easy->hrtf->N; i > 0; i--)
213 {
214 *IRleft++ = *fl++;
215 *IRright++ = *fr++;
216 }
217 }
218
mysofa_getfilter_float(struct MYSOFA_EASY * easy,float x,float y,float z,float * IRleft,float * IRright,float * delayLeft,float * delayRight)219 MYSOFA_EXPORT void mysofa_getfilter_float(struct MYSOFA_EASY *easy, float x,
220 float y, float z, float *IRleft,
221 float *IRright, float *delayLeft,
222 float *delayRight)
223 {
224 mysofa_getfilter_float_advanced(easy, x, y, z, IRleft, IRright, delayLeft,
225 delayRight, true);
226 }
227
228 MYSOFA_EXPORT void
mysofa_getfilter_float_nointerp(struct MYSOFA_EASY * easy,float x,float y,float z,float * IRleft,float * IRright,float * delayLeft,float * delayRight)229 mysofa_getfilter_float_nointerp(struct MYSOFA_EASY *easy, float x, float y,
230 float z, float *IRleft, float *IRright,
231 float *delayLeft, float *delayRight)
232 {
233 mysofa_getfilter_float_advanced(easy, x, y, z, IRleft, IRright, delayLeft,
234 delayRight, false);
235 }
236
mysofa_close(struct MYSOFA_EASY * easy)237 MYSOFA_EXPORT void mysofa_close(struct MYSOFA_EASY *easy)
238 {
239 if (easy)
240 {
241 if (easy->fir)
242 free(easy->fir);
243 if (easy->neighborhood)
244 mysofa_neighborhood_free(easy->neighborhood);
245 if (easy->lookup)
246 mysofa_lookup_free(easy->lookup);
247 if (easy->hrtf)
248 mysofa_free(easy->hrtf);
249 free(easy);
250 }
251 }
252
mysofa_close_cached(struct MYSOFA_EASY * easy)253 MYSOFA_EXPORT void mysofa_close_cached(struct MYSOFA_EASY *easy)
254 {
255 mysofa_cache_release(easy);
256 }
257