1#!/usr/bin/env python3 2# 3# Run: 4# misc/make_resamplers.py | indent -kr -i3 -l0 5 6import sys, re 7 8# http://code.activestate.com/recipes/502257/ 9def interp(string): 10 locals = sys._getframe(1).f_locals 11 globals = sys._getframe(1).f_globals 12 for item in re.findall(r'#\{([^}]*)\}', string): 13 string = string.replace('#{%s}' % item, str(eval(item, globals, locals))) 14 return string 15 16 17class Depth: 18 def index(self, fmt): 19 if fmt == "f32": 20 return self.index_f32 21 if fmt == "s16": 22 return self.index_s16 23 24class Depth_f32(Depth): 25 def constant(self): 26 return "ALLEGRO_AUDIO_DEPTH_FLOAT32" 27 def index_f32(self, buf, index): 28 return interp("#{buf}.f32[ #{index} ]") 29 def index_s16(self, buf, index): 30 return interp("(int16_t) (#{buf}.f32[ #{index} ] * 0x7FFF)") 31 32class Depth_int24(Depth): 33 def constant(self): 34 return "ALLEGRO_AUDIO_DEPTH_INT24" 35 def index_f32(self, buf, index): 36 return interp("(float) #{buf}.s24[ #{index} ] / ((float)0x7FFFFF + 0.5f)") 37 def index_s16(self, buf, index): 38 return interp("(int16_t) (#{buf}.s24[ #{index} ] >> 9)") 39 40class Depth_uint24(Depth): 41 def constant(self): 42 return "ALLEGRO_AUDIO_DEPTH_UINT24" 43 def index_f32(self, buf, index): 44 return interp("(float) #{buf}.u24[ #{index} ] / ((float)0x7FFFFF + 0.5f) - 1.0f") 45 def index_s16(self, buf, index): 46 return interp("(int16_t) ((#{buf}.u24[ #{index} ] - 0x800000) >> 9)") 47 48class Depth_int16(Depth): 49 def constant(self): 50 return "ALLEGRO_AUDIO_DEPTH_INT16" 51 def index_f32(self, buf, index): 52 return interp("(float) #{buf}.s16[ #{index} ] / ((float)0x7FFF + 0.5f)") 53 def index_s16(self, buf, index): 54 return interp("#{buf}.s16[ #{index} ]") 55 56class Depth_uint16(Depth): 57 def constant(self): 58 return "ALLEGRO_AUDIO_DEPTH_UINT16" 59 def index_f32(self, buf, index): 60 return interp("(float) #{buf}.u16[ #{index} ] / ((float)0x7FFF + 0.5f) - 1.0f") 61 def index_s16(self, buf, index): 62 return interp("(int16_t) (#{buf}.u16[ #{index} ] - 0x8000)") 63 64class Depth_int8(Depth): 65 def constant(self): 66 return "ALLEGRO_AUDIO_DEPTH_INT8" 67 def index_f32(self, buf, index): 68 return interp("(float) #{buf}.s8[ #{index} ] / ((float)0x7F + 0.5f)") 69 def index_s16(self, buf, index): 70 return interp("(int16_t) #{buf}.s8[ #{index} ] << 7") 71 72class Depth_uint8(Depth): 73 def constant(self): 74 return "ALLEGRO_AUDIO_DEPTH_UINT8" 75 def index_f32(self, buf, index): 76 return interp("(float) #{buf}.u8[ #{index} ] / ((float)0x7F + 0.5f) - 1.0f") 77 def index_s16(self, buf, index): 78 return interp("(int16_t) (#{buf}.u8[ #{index} ] - 0x80) << 7") 79 80depths = [ 81 Depth_f32(), 82 Depth_int24(), 83 Depth_uint24(), 84 Depth_int16(), 85 Depth_uint16(), 86 Depth_int8(), 87 Depth_uint8() 88] 89 90def make_point_interpolator(name, fmt): 91 print(interp("""\ 92 static INLINE const void * 93 #{name} 94 (SAMP_BUF *samp_buf, 95 const ALLEGRO_SAMPLE_INSTANCE *spl, 96 unsigned int maxc) 97 { 98 unsigned int i0 = spl->pos*maxc; 99 unsigned int i; 100 101 switch (spl->spl_data.depth) { 102 """)) 103 104 for depth in depths: 105 buf_index = depth.index(fmt)("spl->spl_data.buffer", "i0 + i") 106 print(interp("""\ 107 case #{depth.constant()}: 108 for (i = 0; i < maxc; i++) { 109 samp_buf-> #{fmt} [i] = #{buf_index}; 110 } 111 break; 112 """)) 113 114 print(interp("""\ 115 } 116 return samp_buf-> #{fmt} ; 117 }""")) 118 119def make_linear_interpolator(name, fmt): 120 assert fmt == "f32" or fmt == "s16" 121 122 print(interp("""\ 123 static INLINE const void * 124 #{name} 125 (SAMP_BUF *samp_buf, 126 const ALLEGRO_SAMPLE_INSTANCE *spl, 127 unsigned int maxc) 128 { 129 int p0 = spl->pos; 130 int p1 = spl->pos+1; 131 132 switch (spl->loop) { 133 case ALLEGRO_PLAYMODE_ONCE: 134 if (p1 >= spl->spl_data.len) 135 p1 = p0; 136 break; 137 case ALLEGRO_PLAYMODE_LOOP: 138 if (p1 >= spl->loop_end) 139 p1 = spl->loop_start; 140 break; 141 case ALLEGRO_PLAYMODE_BIDIR: 142 if (p1 >= spl->loop_end) { 143 p1 = spl->loop_end - 1; 144 if (p1 < spl->loop_start) 145 p1 = spl->loop_start; 146 } 147 break; 148 case _ALLEGRO_PLAYMODE_STREAM_ONCE: 149 case _ALLEGRO_PLAYMODE_STREAM_ONEDIR:""" + 150 # For audio streams, sample i+1 may be in the next buffer fragment, 151 # which may not even be generated yet. So we lag by one sample and 152 # interpolate between sample i-1 and sample i. 153 # 154 # We arrange the buffers in memory such that indexing i-1 is always 155 # valid, even after wrapping around from the last buffer fragment to 156 # the first buffer fragment. See _al_kcm_refill_stream. 157 """ 158 p0--; 159 p1--; 160 break; 161 } 162 163 p0 *= maxc; 164 p1 *= maxc; 165 166 switch (spl->spl_data.depth) { 167 """)) 168 169 for depth in depths: 170 x0 = depth.index(fmt)("spl->spl_data.buffer", "p0 + i") 171 x1 = depth.index(fmt)("spl->spl_data.buffer", "p1 + i") 172 print(interp("""\ 173 case #{depth.constant()}: 174 {""")) 175 176 if fmt == "f32": 177 print(interp("""\ 178 const float t = (float)spl->pos_bresenham_error / spl->step_denom; 179 int i; 180 for (i = 0; i < (int)maxc; i++) { 181 const float x0 = #{x0}; 182 const float x1 = #{x1}; 183 const float s = (x0 * (1.0f - t)) + (x1 * t); 184 samp_buf->f32[i] = s; 185 }""")) 186 elif fmt == "s16": 187 print(interp("""\ 188 const int32_t t = 256 * spl->pos_bresenham_error / spl->step_denom; 189 int i; 190 for (i = 0; i < (int)maxc; i++) { 191 const int32_t x0 = #{x0}; 192 const int32_t x1 = #{x1}; 193 const int32_t s = ((x0 * (256 - t))>>8) + ((x1 * t)>>8); 194 samp_buf->s16[i] = (int16_t)s; 195 }""")) 196 197 print(interp("""\ 198 } 199 break; 200 """)) 201 202 print(interp("""\ 203 } 204 return samp_buf-> #{fmt}; 205 }""")) 206 207def make_cubic_interpolator(name, fmt): 208 assert fmt == "f32" 209 210 print(interp("""\ 211 static INLINE const void * 212 #{name} 213 (SAMP_BUF *samp_buf, 214 const ALLEGRO_SAMPLE_INSTANCE *spl, 215 unsigned int maxc) 216 { 217 int p0 = spl->pos-1; 218 int p1 = spl->pos; 219 int p2 = spl->pos+1; 220 int p3 = spl->pos+2; 221 222 switch (spl->loop) { 223 case ALLEGRO_PLAYMODE_ONCE: 224 if (p0 < 0) 225 p0 = 0; 226 if (p2 >= spl->spl_data.len) 227 p2 = spl->spl_data.len - 1; 228 if (p3 >= spl->spl_data.len) 229 p3 = spl->spl_data.len - 1; 230 break; 231 case ALLEGRO_PLAYMODE_LOOP: 232 case ALLEGRO_PLAYMODE_BIDIR: 233 /* These positions should really wrap/bounce instead of clamping 234 * but it's probably unnoticeable. 235 */ 236 if (p0 < spl->loop_start) 237 p0 = spl->loop_end - 1; 238 if (p2 >= spl->loop_end) 239 p2 = spl->loop_start; 240 if (p3 >= spl->loop_end) 241 p3 = spl->loop_start; 242 break; 243 case _ALLEGRO_PLAYMODE_STREAM_ONCE: 244 case _ALLEGRO_PLAYMODE_STREAM_ONEDIR: 245 /* Lag by three samples in total. */ 246 p0 -= 2; 247 p1 -= 2; 248 p2 -= 2; 249 p3 -= 2; 250 break; 251 } 252 253 p0 *= maxc; 254 p1 *= maxc; 255 p2 *= maxc; 256 p3 *= maxc; 257 258 switch (spl->spl_data.depth) { 259 """)) 260 261 for depth in depths: 262 value0 = depth.index(fmt)("spl->spl_data.buffer", "p0 + i") 263 value1 = depth.index(fmt)("spl->spl_data.buffer", "p1 + i") 264 value2 = depth.index(fmt)("spl->spl_data.buffer", "p2 + i") 265 value3 = depth.index(fmt)("spl->spl_data.buffer", "p3 + i") 266 # 4-point, cubic Hermite interpolation 267 # Code transcribed from "Polynomial Interpolators for High-Quality 268 # Resampling of Oversampled Audio" by Olli Niemitalo 269 # http://yehar.com/blog/?p=197 270 print(interp("""\ 271 case #{depth.constant()}: 272 { 273 const float t = (float)spl->pos_bresenham_error / spl->step_denom; 274 signed int i; 275 for (i = 0; i < (signed int)maxc; i++) { 276 float x0 = #{value0}; 277 float x1 = #{value1}; 278 float x2 = #{value2}; 279 float x3 = #{value3}; 280 float c0 = x1; 281 float c1 = 0.5f * (x2 - x0); 282 float c2 = x0 - (2.5f * x1) + (2.0f * x2) - (0.5f * x3); 283 float c3 = (0.5f * (x3 - x0)) + (1.5f * (x1 - x2)); 284 float s = (((((c3 * t) + c2) * t) + c1) * t) + c0; 285 samp_buf->f32[i] = s; 286 } 287 } 288 break; 289 """)) 290 291 print(interp("""\ 292 } 293 return samp_buf-> #{fmt} ; 294 }""")) 295 296if __name__ == "__main__": 297 print("// Warning: This file was created by make_resamplers.py - do not edit.") 298 print("// vim: set ft=c:") 299 300 make_point_interpolator("point_spl32", "f32") 301 make_point_interpolator("point_spl16", "s16") 302 make_linear_interpolator("linear_spl32", "f32") 303 make_linear_interpolator("linear_spl16", "s16") 304 make_cubic_interpolator("cubic_spl32", "f32") 305 306# vim: set sts=3 sw=3 et: 307