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