gosu 1.4.1 → 1.4.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/dependencies/SDL_sound/SDL_sound.c +21 -63
  3. data/dependencies/SDL_sound/SDL_sound.h +2 -2
  4. data/dependencies/SDL_sound/SDL_sound_aiff.c +26 -23
  5. data/dependencies/SDL_sound/SDL_sound_au.c +8 -8
  6. data/dependencies/SDL_sound/SDL_sound_coreaudio.c +4 -5
  7. data/dependencies/SDL_sound/SDL_sound_flac.c +28 -30
  8. data/dependencies/SDL_sound/SDL_sound_internal.h +4 -4
  9. data/dependencies/SDL_sound/SDL_sound_modplug.c +1 -1
  10. data/dependencies/SDL_sound/SDL_sound_mp3.c +19 -23
  11. data/dependencies/SDL_sound/SDL_sound_raw.c +5 -6
  12. data/dependencies/SDL_sound/SDL_sound_shn.c +4 -4
  13. data/dependencies/SDL_sound/SDL_sound_voc.c +15 -15
  14. data/dependencies/SDL_sound/SDL_sound_vorbis.c +14 -7
  15. data/dependencies/SDL_sound/SDL_sound_wav.c +17 -17
  16. data/dependencies/SDL_sound/dr_flac.h +10840 -4779
  17. data/dependencies/SDL_sound/dr_mp3.h +2793 -1004
  18. data/dependencies/SDL_sound/libmodplug/fastmix.c +5 -0
  19. data/dependencies/SDL_sound/libmodplug/load_669.c +1 -1
  20. data/dependencies/SDL_sound/libmodplug/load_amf.c +1 -0
  21. data/dependencies/SDL_sound/libmodplug/load_ams.c +38 -22
  22. data/dependencies/SDL_sound/libmodplug/load_it.c +18 -14
  23. data/dependencies/SDL_sound/libmodplug/load_mdl.c +18 -9
  24. data/dependencies/SDL_sound/libmodplug/load_med.c +7 -6
  25. data/dependencies/SDL_sound/libmodplug/load_mt2.c +36 -17
  26. data/dependencies/SDL_sound/libmodplug/load_okt.c +51 -24
  27. data/dependencies/SDL_sound/libmodplug/load_psm.c +4 -2
  28. data/dependencies/SDL_sound/libmodplug/load_s3m.c +4 -4
  29. data/dependencies/SDL_sound/libmodplug/load_ult.c +4 -3
  30. data/dependencies/SDL_sound/libmodplug/load_xm.c +5 -5
  31. data/dependencies/SDL_sound/libmodplug/snd_fx.c +8 -1
  32. data/dependencies/SDL_sound/libmodplug/sndfile.c +21 -4
  33. data/dependencies/SDL_sound/stb_vorbis.h +10 -18
  34. data/dependencies/mojoAL/mojoal.c +260 -6
  35. data/dependencies/stb/stb_image.h +208 -73
  36. data/dependencies/stb/stb_image_write.h +57 -23
  37. data/dependencies/stb/stb_truetype.h +345 -279
  38. data/dependencies/utf8proc/utf8proc.c +37 -18
  39. data/dependencies/utf8proc/utf8proc.h +17 -5
  40. data/dependencies/utf8proc/utf8proc_data.h +12012 -10089
  41. data/include/Gosu/Buttons.hpp +103 -103
  42. data/include/Gosu/Directories.hpp +31 -24
  43. data/include/Gosu/Font.hpp +4 -2
  44. data/include/Gosu/Gosu.hpp +5 -8
  45. data/include/Gosu/IO.hpp +0 -3
  46. data/include/Gosu/Math.hpp +0 -3
  47. data/include/Gosu/Timing.hpp +2 -8
  48. data/include/Gosu/Version.hpp +1 -1
  49. data/src/AudioImpl.cpp +0 -7
  50. data/src/AudioImpl.hpp +1 -3
  51. data/src/BitmapIO.cpp +23 -2
  52. data/src/DirectoriesApple.cpp +25 -24
  53. data/src/DirectoriesUnix.cpp +14 -12
  54. data/src/DirectoriesWin.cpp +26 -30
  55. data/src/Font.cpp +12 -2
  56. data/src/Image.cpp +10 -15
  57. data/src/RubyGosu.cxx +6 -34
  58. data/src/TimingApple.cpp +1 -7
  59. data/src/TimingUnix.cpp +0 -6
  60. data/src/TimingWin.cpp +0 -6
  61. data/src/Window.cpp +4 -3
  62. metadata +2 -2
@@ -92,6 +92,7 @@ void CSoundFile_S3MConvert(MODCOMMAND *m, BOOL bIT)
92
92
  case 'X': command = CMD_PANNING8; break;
93
93
  case 'Y': command = CMD_PANBRELLO; break;
94
94
  case 'Z': command = CMD_MIDI; break;
95
+ case '\\': command = CMD_MIDI; break;
95
96
  default: command = 0;
96
97
  }
97
98
  m->command = command;
@@ -165,6 +166,7 @@ BOOL CSoundFile_ReadS3M(CSoundFile *_this, const BYTE *lpStream, DWORD dwMemLeng
165
166
  UINT iord = psfh.ordnum;
166
167
  if (iord<1) iord = 1;
167
168
  if (iord > MAX_ORDERS) iord = MAX_ORDERS;
169
+ if (dwMemPos + iord + 1 >= dwMemLength) return FALSE;
168
170
  if (iord)
169
171
  {
170
172
  if (dwMemPos + iord > dwMemLength) return FALSE;
@@ -185,8 +187,7 @@ BOOL CSoundFile_ReadS3M(CSoundFile *_this, const BYTE *lpStream, DWORD dwMemLeng
185
187
 
186
188
  if (nins+npat)
187
189
  {
188
- if (2*(nins+npat) + dwMemPos > dwMemLength) return FALSE;
189
-
190
+ if (dwMemPos + 2*(nins+npat) >= dwMemLength) return FALSE;
190
191
  SDL_memcpy(ptr, lpStream+dwMemPos, 2*(nins+npat));
191
192
  dwMemPos += 2*(nins+npat);
192
193
  for (UINT j = 0; j < (nins+npat); ++j) {
@@ -194,9 +195,8 @@ BOOL CSoundFile_ReadS3M(CSoundFile *_this, const BYTE *lpStream, DWORD dwMemLeng
194
195
  }
195
196
  if (psfh.panning_present == 252)
196
197
  {
197
- if (dwMemPos + 32 > dwMemLength) return FALSE;
198
-
199
198
  const BYTE *chnpan = lpStream+dwMemPos;
199
+ if (dwMemPos > dwMemLength - 32) return FALSE;
200
200
  for (UINT i=0; i<32; i++) if (chnpan[i] & 0x20)
201
201
  {
202
202
  _this->ChnSettings[i].nPan = ((chnpan[i] & 0x0F) << 4) + 8;
@@ -128,7 +128,7 @@ BOOL CSoundFile_ReadUlt(CSoundFile *_this, const BYTE *lpStream, DWORD dwMemLeng
128
128
  for (UINT nPat=0; nPat<nop; nPat++)
129
129
  {
130
130
  MODCOMMAND *pat = NULL;
131
-
131
+
132
132
  if (nPat < MAX_PATTERNS)
133
133
  {
134
134
  pat = _this->Patterns[nPat];
@@ -137,16 +137,17 @@ BOOL CSoundFile_ReadUlt(CSoundFile *_this, const BYTE *lpStream, DWORD dwMemLeng
137
137
  UINT row = 0;
138
138
  while (row < 64)
139
139
  {
140
- if (dwMemPos + 5 > dwMemLength) return TRUE;
140
+ if (dwMemPos > dwMemLength - 5) return TRUE;
141
141
  UINT rep = 1;
142
142
  UINT note = lpStream[dwMemPos++];
143
143
  if (note == 0xFC)
144
144
  {
145
- if (dwMemPos + 7 > dwMemLength) return TRUE;
146
145
  rep = lpStream[dwMemPos];
147
146
  note = lpStream[dwMemPos+1];
148
147
  dwMemPos += 2;
148
+ if (dwMemPos > dwMemLength - 4) return TRUE;
149
149
  }
150
+
150
151
  UINT instr = lpStream[dwMemPos++];
151
152
  UINT eff = lpStream[dwMemPos++];
152
153
  UINT dat1 = lpStream[dwMemPos++];
@@ -188,11 +188,11 @@ BOOL CSoundFile_ReadXM(CSoundFile *_this, const BYTE *lpStream, DWORD dwMemLengt
188
188
  UINT vol = 0;
189
189
  if (b & 0x80)
190
190
  {
191
- if ((b & 1) && j < packsize) p->note = src[j++];
192
- if ((b & 2) && j < packsize) p->instr = src[j++];
193
- if ((b & 4) && j < packsize) vol = src[j++];
194
- if ((b & 8) && j < packsize) p->command = src[j++];
195
- if ((b & 16) && j < packsize) p->param = src[j++];
191
+ if (b & 1) p->note = j < packsize ? src[j++] : 0;
192
+ if (b & 2) p->instr = j < packsize ? src[j++] : 0;
193
+ if (b & 4) vol = j < packsize ? src[j++] : 0;
194
+ if (b & 8) p->command = j < packsize ? src[j++] : 0;
195
+ if (b & 16) p->param = j < packsize ? src[j++] : 0;
196
196
  } else
197
197
  {
198
198
  if (j + 5 > packsize) break;
@@ -420,7 +420,14 @@ void CSoundFile_NoteChange(CSoundFile *_this, UINT nChn, int note, BOOL bPorta,
420
420
  if (note >= 0x80) // 0xFE or invalid note => key off
421
421
  {
422
422
  // Key Off
423
- CSoundFile_KeyOff(_this, nChn);
423
+ if (note < 0xFD && _this->m_nType == MOD_TYPE_IT)
424
+ {
425
+ if (_this->m_nInstruments)
426
+ pChn->dwFlags |= CHN_NOTEFADE;
427
+ } else
428
+ {
429
+ CSoundFile_KeyOff(_this, nChn);
430
+ }
424
431
  // Note Cut
425
432
  if (note == 0xFE)
426
433
  {
@@ -14,8 +14,8 @@ extern BOOL MMCMP_Unpack(LPCBYTE *ppMemFile, LPDWORD pdwMemLength);
14
14
  extern void AMSUnpack(const char *psrc, UINT inputlen, char *pdest, UINT dmax, char packcharacter);
15
15
  extern WORD MDLReadBits(DWORD *bitbuf, UINT *bitnum, LPBYTE *ibuf, CHAR n);
16
16
  extern int DMFUnpack(LPBYTE psample, LPBYTE ibuf, LPBYTE ibufmax, UINT maxlen);
17
- extern void ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215);
18
- extern void ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, BOOL b215);
17
+ extern DWORD ITUnpack8Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, DWORD channels, BOOL b215);
18
+ extern DWORD ITUnpack16Bit(signed char *pSample, DWORD dwLen, LPBYTE lpMemFile, DWORD dwMemLength, DWORD channels, BOOL b215);
19
19
 
20
20
 
21
21
  static void CSoundFile_UpdateSettings(CSoundFile *_this, const ModPlug_Settings *settings)
@@ -665,9 +665,26 @@ UINT CSoundFile_ReadSample(CSoundFile *_this, MODINSTRUMENT *pIns, UINT nFlags,
665
665
  len = dwMemLength;
666
666
  if (len < 4) break;
667
667
  if ((nFlags == RS_IT2148) || (nFlags == RS_IT2158))
668
- ITUnpack8Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, (nFlags == RS_IT2158));
668
+ ITUnpack8Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, 1, (nFlags == RS_IT2158));
669
669
  else
670
- ITUnpack16Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, (nFlags == RS_IT21516));
670
+ ITUnpack16Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, 1, (nFlags == RS_IT21516));
671
+ break;
672
+
673
+ case RS_IT2148 | RSF_STEREO:
674
+ case RS_IT21416 | RSF_STEREO:
675
+ case RS_IT2158 | RSF_STEREO:
676
+ case RS_IT21516 | RSF_STEREO:
677
+ len = dwMemLength;
678
+ if (len < 4) break;
679
+ if ((nFlags == (RS_IT2148 | RSF_STEREO)) || (nFlags == (RS_IT2158 | RSF_STEREO)))
680
+ {
681
+ DWORD offset = ITUnpack8Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, 2, (nFlags == (RS_IT2158 | RSF_STEREO)));
682
+ ITUnpack8Bit(pIns->pSample + 1, pIns->nLength, (LPBYTE)lpMemFile + offset, dwMemLength - offset, 2, (nFlags == (RS_IT2158 | RSF_STEREO)));
683
+ } else
684
+ {
685
+ DWORD offset = ITUnpack16Bit(pIns->pSample, pIns->nLength, (LPBYTE)lpMemFile, dwMemLength, 2, (nFlags == (RS_IT21516 | RSF_STEREO)));
686
+ ITUnpack16Bit(pIns->pSample + 2, pIns->nLength, (LPBYTE)lpMemFile + offset, dwMemLength - offset, 2, (nFlags == (RS_IT21516 | RSF_STEREO)));
687
+ }
671
688
  break;
672
689
 
673
690
  #ifndef MODPLUG_BASIC_SUPPORT
@@ -608,21 +608,6 @@ enum STBVorbisError
608
608
 
609
609
  #include <limits.h>
610
610
 
611
- /* we need alloca() regardless of STB_VORBIS_NO_CRT,
612
- * because there is not a corresponding 'dealloca' */
613
- #if !defined(alloca)
614
- # if defined(HAVE_ALLOCA_H)
615
- # include <alloca.h>
616
- # elif defined(__GNUC__)
617
- # define alloca __builtin_alloca
618
- # elif defined(_MSC_VER)
619
- # include <malloc.h>
620
- # define alloca _alloca
621
- # elif defined(__WATCOMC__)
622
- # include <malloc.h>
623
- # endif
624
- #endif
625
-
626
611
  #ifndef STB_FORCEINLINE
627
612
  #if defined(_MSC_VER)
628
613
  #define STB_FORCEINLINE __forceinline
@@ -646,7 +631,7 @@ enum STBVorbisError
646
631
  #include <crtdbg.h>
647
632
  #define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1])
648
633
  #else
649
- #define CHECK(f) ((void) 0)
634
+ #define CHECK(f) do {} while(0)
650
635
  #endif
651
636
 
652
637
  #define MAX_BLOCKSIZE_LOG 13 // from specification
@@ -937,6 +922,9 @@ struct stb_vorbis
937
922
  int channel_buffer_start;
938
923
  int channel_buffer_end;
939
924
 
925
+ // hack: decode work buffer (used in inverse_mdct and decode_residues)
926
+ void *work_buffer;
927
+
940
928
  // temporary buffers
941
929
  void *temp_lengths;
942
930
  void *temp_codewords;
@@ -971,8 +959,8 @@ static int error(vorb *f, enum STBVorbisError e)
971
959
 
972
960
  #define array_size_required(count,size) (count*(sizeof(void *)+(size)))
973
961
 
974
- #define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size))
975
- #define temp_free(f,p) (void)0
962
+ #define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : f->work_buffer)
963
+ #define temp_free(f,p) do {} while (0)
976
964
  #define temp_alloc_save(f) ((f)->temp_offset)
977
965
  #define temp_alloc_restore(f,p) ((f)->temp_offset = (p))
978
966
 
@@ -4297,6 +4285,9 @@ static int start_decoder(vorb *f)
4297
4285
  // check if there's enough temp memory so we don't error later
4298
4286
  if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset)
4299
4287
  return error(f, VORBIS_outofmem);
4288
+ } else {
4289
+ f->work_buffer = setup_malloc(f, f->temp_memory_required);
4290
+ if (f->work_buffer == NULL) return error(f, VORBIS_outofmem);
4300
4291
  }
4301
4292
 
4302
4293
  // @TODO: stb_vorbis_seek_start expects first_audio_page_offset to point to a page
@@ -4376,6 +4367,7 @@ static void vorbis_deinit(stb_vorbis *p)
4376
4367
  setup_free(p, p->bit_reverse[i]);
4377
4368
  }
4378
4369
  if (!p->alloc.alloc_buffer) {
4370
+ setup_free(p, p->work_buffer);
4379
4371
  setup_temp_free(p, &p->temp_lengths, 0);
4380
4372
  setup_temp_free(p, &p->temp_codewords, 0);
4381
4373
  setup_temp_free(p, &p->temp_values, 0);
@@ -230,6 +230,12 @@ static int has_neon = 0;
230
230
  #endif
231
231
  #endif
232
232
 
233
+ /* no threads in Emscripten (at the moment...!) */
234
+ #if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__)
235
+ #define init_api_lock() 1
236
+ #define grab_api_lock()
237
+ #define ungrab_api_lock()
238
+ #else
233
239
  static SDL_mutex *api_lock = NULL;
234
240
 
235
241
  static int init_api_lock(void)
@@ -264,6 +270,7 @@ static void ungrab_api_lock(void)
264
270
  const int rc = SDL_UnlockMutex(api_lock);
265
271
  SDL_assert(rc == 0);
266
272
  }
273
+ #endif
267
274
 
268
275
  #define ENTRYPOINT(rettype,fn,params,args) \
269
276
  rettype fn params { rettype retval; grab_api_lock(); retval = _##fn args ; ungrab_api_lock(); return retval; }
@@ -417,6 +424,23 @@ typedef struct BufferQueue
417
424
  SDL_atomic_t num_items; /* counts just_queued+head/tail */
418
425
  } BufferQueue;
419
426
 
427
+ #define pitch_framesize 1024
428
+ #define pitch_framesize2 512
429
+ typedef struct PitchState
430
+ {
431
+ /* !!! FIXME: this is a wild amount of memory for pitch-shifting! */
432
+ ALfloat infifo[pitch_framesize];
433
+ ALfloat outfifo[pitch_framesize];
434
+ ALfloat workspace[2*pitch_framesize];
435
+ ALfloat lastphase[pitch_framesize2+1];
436
+ ALfloat sumphase[pitch_framesize2+1];
437
+ ALfloat outputaccum[2*pitch_framesize];
438
+ ALfloat synmagn[pitch_framesize2+1];
439
+ ALfloat synfreq[pitch_framesize2+1];
440
+ ALint rover;
441
+ } PitchState;
442
+
443
+
420
444
  typedef struct ALsource ALsource;
421
445
 
422
446
  SIMDALIGNEDSTRUCT ALsource
@@ -452,6 +476,7 @@ SIMDALIGNEDSTRUCT ALsource
452
476
  ALboolean offset_latched; /* AL_SEC_OFFSET, etc, say set values apply to next alSourcePlay if not currently playing! */
453
477
  ALint queue_channels;
454
478
  ALsizei queue_frequency;
479
+ PitchState *pitchstate;
455
480
  ALsource *playlist_next; /* linked list that contains currently-playing sources! Only touched by mixer thread! */
456
481
  };
457
482
 
@@ -1124,8 +1149,222 @@ static void mix_float32_c2_neon(const ALfloat * restrict panning, const float *
1124
1149
  #endif
1125
1150
 
1126
1151
 
1127
- static void mix_buffer(const ALbuffer *buffer, const ALfloat * restrict panning, const float * restrict data, float * restrict stream, const ALsizei mixframes)
1152
+ /****************************************************************************
1153
+ *
1154
+ * pitch_fft and pitch_shift are modified versions of code from:
1155
+ *
1156
+ * http://blogs.zynaptiq.com/bernsee/pitch-shifting-using-the-ft/
1157
+ *
1158
+ * The original code has this copyright/license:
1159
+ *
1160
+ *****************************************************************************
1161
+ *
1162
+ * COPYRIGHT 1999-2015 Stephan M. Bernsee <s.bernsee [AT] zynaptiq [DOT] com>
1163
+ *
1164
+ * The Wide Open License (WOL)
1165
+ *
1166
+ * Permission to use, copy, modify, distribute and sell this software and its
1167
+ * documentation for any purpose is hereby granted without fee, provided that
1168
+ * the above copyright notice and this license appear in all source copies.
1169
+ * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF
1170
+ * ANY KIND. See http://www.dspguru.com/wol.htm for more information.
1171
+ *
1172
+ *****************************************************************************/
1173
+
1174
+ /* FFT routine, (C)1996 S.M.Bernsee. */
1175
+ static void pitch_fft(float *fftBuffer, int fftFrameSize, int sign)
1176
+ {
1177
+ float wr, wi, arg, *p1, *p2, temp;
1178
+ float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
1179
+ int i, bitm, j, le, le2, k;
1180
+
1181
+ for (i = 2; i < 2*fftFrameSize-2; i += 2) {
1182
+ for (bitm = 2, j = 0; bitm < 2*fftFrameSize; bitm <<= 1) {
1183
+ if (i & bitm) j++;
1184
+ j <<= 1;
1185
+ }
1186
+ if (i < j) {
1187
+ p1 = fftBuffer+i; p2 = fftBuffer+j;
1188
+ temp = *p1; *(p1++) = *p2;
1189
+ *(p2++) = temp; temp = *p1;
1190
+ *p1 = *p2; *p2 = temp;
1191
+ }
1192
+ }
1193
+ const int endval = (int)(SDL_log(fftFrameSize)/SDL_log(2.)+.5); /* !!! FIXME: precalc this. */
1194
+ for (k = 0, le = 2; k < endval; k++) {
1195
+ le <<= 1;
1196
+ le2 = le>>1;
1197
+ ur = 1.0;
1198
+ ui = 0.0;
1199
+ arg = M_PI / (le2>>1);
1200
+ wr = SDL_cos(arg);
1201
+ wi = sign*SDL_sin(arg);
1202
+ for (j = 0; j < le2; j += 2) {
1203
+ p1r = fftBuffer+j; p1i = p1r+1;
1204
+ p2r = p1r+le2; p2i = p2r+1;
1205
+ for (i = j; i < 2*fftFrameSize; i += le) {
1206
+ tr = *p2r * ur - *p2i * ui;
1207
+ ti = *p2r * ui + *p2i * ur;
1208
+ *p2r = *p1r - tr; *p2i = *p1i - ti;
1209
+ *p1r += tr; *p1i += ti;
1210
+ p1r += le; p1i += le;
1211
+ p2r += le; p2i += le;
1212
+ }
1213
+ tr = ur*wr - ui*wi;
1214
+ ui = ur*wi + ui*wr;
1215
+ ur = tr;
1216
+ }
1217
+ }
1218
+ }
1219
+
1220
+ static void pitch_shift(ALsource *src, const ALbuffer *buffer, int numSampsToProcess, const float *indata, float *outdata)
1128
1221
  {
1222
+ const float pitchShift = src->pitch;
1223
+ const float sampleRate = (float) buffer->frequency;
1224
+ const int osamp = 4;
1225
+ const int stepSize = pitch_framesize / osamp;
1226
+ const int inFifoLatency = pitch_framesize - stepSize;
1227
+ const double freqPerBin = sampleRate / (double)pitch_framesize;
1228
+ const double expct = 2.0 * M_PI * ((double)stepSize / (double)pitch_framesize);
1229
+
1230
+ double magn, phase, tmp, window, real, imag;
1231
+ int i,k, qpd, index;
1232
+ PitchState *state = src->pitchstate;
1233
+
1234
+ SDL_assert(state != NULL);
1235
+
1236
+ if (state->rover == 0) state->rover = inFifoLatency;
1237
+
1238
+ /* main processing loop */
1239
+ for (i = 0; i < numSampsToProcess; i++){
1240
+
1241
+ /* As long as we have not yet collected enough data just read in */
1242
+ state->infifo[state->rover] = indata[i];
1243
+ outdata[i] = state->outfifo[state->rover-inFifoLatency];
1244
+ state->rover++;
1245
+
1246
+ /* now we have enough data for processing */
1247
+ if (state->rover >= pitch_framesize) {
1248
+ state->rover = inFifoLatency;
1249
+
1250
+ /* do windowing and re,im interleave */
1251
+ for (k = 0; k < pitch_framesize;k++) {
1252
+ window = -.5*SDL_cos(2.*M_PI*(double)k/(double)pitch_framesize)+.5;
1253
+ state->workspace[2*k] = state->infifo[k] * window;
1254
+ state->workspace[2*k+1] = 0.;
1255
+ }
1256
+
1257
+
1258
+ /* ***************** ANALYSIS ******************* */
1259
+ /* do transform */
1260
+ pitch_fft(state->workspace, pitch_framesize, -1);
1261
+
1262
+ /* this is the analysis step */
1263
+ for (k = 0; k <= pitch_framesize2; k++) {
1264
+
1265
+ /* de-interlace FFT buffer */
1266
+ real = state->workspace[2*k];
1267
+ imag = state->workspace[2*k+1];
1268
+
1269
+ /* compute magnitude and phase */
1270
+ magn = 2.*SDL_sqrt(real*real + imag*imag);
1271
+ phase = SDL_atan2(imag,real);
1272
+
1273
+ /* compute phase difference */
1274
+ tmp = phase - state->lastphase[k];
1275
+ state->lastphase[k] = phase;
1276
+
1277
+ /* subtract expected phase difference */
1278
+ tmp -= (double)k*expct;
1279
+
1280
+ /* map delta phase into +/- Pi interval */
1281
+ qpd = tmp/M_PI;
1282
+ if (qpd >= 0) qpd += qpd&1;
1283
+ else qpd -= qpd&1;
1284
+ tmp -= M_PI*(double)qpd;
1285
+
1286
+ /* get deviation from bin frequency from the +/- Pi interval */
1287
+ tmp = osamp*tmp/(2.*M_PI);
1288
+
1289
+ /* compute the k-th partials' true frequency */
1290
+ tmp = (double)k*freqPerBin + tmp*freqPerBin;
1291
+
1292
+ /* store magnitude and true frequency in analysis arrays */
1293
+ state->workspace[2*k] = magn;
1294
+ state->workspace[2*k+1] = tmp;
1295
+
1296
+ }
1297
+
1298
+ /* ***************** PROCESSING ******************* */
1299
+ /* this does the actual pitch shifting */
1300
+ SDL_memset(state->synmagn, '\0', sizeof (state->synmagn));
1301
+ for (k = 0; k <= pitch_framesize2; k++) {
1302
+ index = k*pitchShift;
1303
+ if (index <= pitch_framesize2) {
1304
+ state->synmagn[index] += state->workspace[2*k];
1305
+ state->synfreq[index] = state->workspace[2*k+1] * pitchShift;
1306
+ }
1307
+ }
1308
+
1309
+ /* ***************** SYNTHESIS ******************* */
1310
+ /* this is the synthesis step */
1311
+ for (k = 0; k <= pitch_framesize2; k++) {
1312
+
1313
+ /* get magnitude and true frequency from synthesis arrays */
1314
+ magn = state->synmagn[k];
1315
+ tmp = state->synfreq[k];
1316
+
1317
+ /* subtract bin mid frequency */
1318
+ tmp -= (double)k*freqPerBin;
1319
+
1320
+ /* get bin deviation from freq deviation */
1321
+ tmp /= freqPerBin;
1322
+
1323
+ /* take osamp into account */
1324
+ tmp = 2.*M_PI*tmp/osamp;
1325
+
1326
+ /* add the overlap phase advance back in */
1327
+ tmp += (double)k*expct;
1328
+
1329
+ /* accumulate delta phase to get bin phase */
1330
+ state->sumphase[k] += tmp;
1331
+ phase = state->sumphase[k];
1332
+
1333
+ /* get real and imag part and re-interleave */
1334
+ state->workspace[2*k] = magn*SDL_cos(phase);
1335
+ state->workspace[2*k+1] = magn*SDL_sin(phase);
1336
+ }
1337
+
1338
+ /* zero negative frequencies */
1339
+ for (k = pitch_framesize+2; k < 2*pitch_framesize; k++) state->workspace[k] = 0.;
1340
+
1341
+ /* do inverse transform */
1342
+ pitch_fft(state->workspace, pitch_framesize, 1);
1343
+
1344
+ /* do windowing and add to output accumulator */
1345
+ for(k=0; k < pitch_framesize; k++) {
1346
+ window = -.5*SDL_cos(2.*M_PI*(double)k/(double)pitch_framesize)+.5;
1347
+ state->outputaccum[k] += 2.*window*state->workspace[2*k]/(pitch_framesize2*osamp);
1348
+ }
1349
+ for (k = 0; k < stepSize; k++) state->outfifo[k] = state->outputaccum[k];
1350
+
1351
+ /* shift accumulator */
1352
+ SDL_memmove(state->outputaccum, state->outputaccum+stepSize, pitch_framesize*sizeof(float));
1353
+
1354
+ /* move input FIFO */
1355
+ for (k = 0; k < inFifoLatency; k++) state->infifo[k] = state->infifo[k+stepSize];
1356
+ }
1357
+ }
1358
+ }
1359
+
1360
+ static void mix_buffer(ALsource *src, const ALbuffer *buffer, const ALfloat * restrict panning, const float * restrict data, float * restrict stream, const ALsizei mixframes)
1361
+ {
1362
+ if ((src->pitch != 1.0f) && (src->pitchstate != NULL)) {
1363
+ float *pitched = (float *) alloca(mixframes * buffer->channels * sizeof (float));
1364
+ pitch_shift(src, buffer, mixframes * buffer->channels, data, pitched);
1365
+ data = pitched;
1366
+ }
1367
+
1129
1368
  const ALfloat left = panning[0];
1130
1369
  const ALfloat right = panning[1];
1131
1370
  FIXME("currently expects output to be stereo");
@@ -1194,7 +1433,7 @@ static ALboolean mix_source_buffer(ALCcontext *ctx, ALsource *src, BufferQueueIt
1194
1433
  const int mixbufframes = mixbuflen / bufferframesize;
1195
1434
  const int getframes = SDL_min(remainingmixframes, mixbufframes);
1196
1435
  SDL_AudioStreamGet(src->stream, mixbuf, getframes * bufferframesize);
1197
- mix_buffer(buffer, src->panning, mixbuf, *stream, getframes);
1436
+ mix_buffer(src, buffer, src->panning, mixbuf, *stream, getframes);
1198
1437
  *len -= getframes * deviceframesize;
1199
1438
  *stream += getframes * ctx->device->channels;
1200
1439
  remainingmixframes -= getframes;
@@ -1202,7 +1441,7 @@ static ALboolean mix_source_buffer(ALCcontext *ctx, ALsource *src, BufferQueueIt
1202
1441
  } else {
1203
1442
  const int framesavail = (buffer->len - src->offset) / bufferframesize;
1204
1443
  const int mixframes = SDL_min(framesneeded, framesavail);
1205
- mix_buffer(buffer, src->panning, data, *stream, mixframes);
1444
+ mix_buffer(src, buffer, src->panning, data, *stream, mixframes);
1206
1445
  src->offset += mixframes * bufferframesize;
1207
1446
  *len -= mixframes * deviceframesize;
1208
1447
  *stream += mixframes * ctx->device->channels;
@@ -3433,6 +3672,19 @@ static ALboolean _alIsSource(const ALuint name)
3433
3672
  }
3434
3673
  ENTRYPOINT(ALboolean,alIsSource,(ALuint name),(name))
3435
3674
 
3675
+ static void source_set_pitch(ALCcontext *ctx, ALsource *src, const ALfloat pitch)
3676
+ {
3677
+ /* only allocate pitchstate if the pitch every changes, because it's a lot of
3678
+ RAM and we leave it allocated to the source until forever once needed */
3679
+ if ((pitch != 1.0f) && (src->pitchstate == NULL)) {
3680
+ src->pitchstate = (PitchState *) SDL_calloc(1, sizeof (PitchState));
3681
+ if (src->pitchstate == NULL) {
3682
+ set_al_error(ctx, AL_OUT_OF_MEMORY);
3683
+ }
3684
+ }
3685
+ src->pitch = pitch;
3686
+ }
3687
+
3436
3688
  static void _alSourcefv(const ALuint name, const ALenum param, const ALfloat *values)
3437
3689
  {
3438
3690
  ALCcontext *ctx = get_current_context();
@@ -3449,7 +3701,7 @@ static void _alSourcefv(const ALuint name, const ALenum param, const ALfloat *va
3449
3701
  case AL_REFERENCE_DISTANCE: src->reference_distance = *values; break;
3450
3702
  case AL_ROLLOFF_FACTOR: src->rolloff_factor = *values; break;
3451
3703
  case AL_MAX_DISTANCE: src->max_distance = *values; break;
3452
- case AL_PITCH: src->pitch = *values; break;
3704
+ case AL_PITCH: source_set_pitch(ctx, src, *values); break;
3453
3705
  case AL_CONE_INNER_ANGLE: src->cone_inner_angle = *values; break;
3454
3706
  case AL_CONE_OUTER_ANGLE: src->cone_outer_angle = *values; break;
3455
3707
  case AL_CONE_OUTER_GAIN: src->cone_outer_gain = *values; break;
@@ -3654,7 +3906,7 @@ static void _alGetSourcefv(const ALuint name, const ALenum param, ALfloat *value
3654
3906
  case AL_REFERENCE_DISTANCE: *values = src->reference_distance; break;
3655
3907
  case AL_ROLLOFF_FACTOR: *values = src->rolloff_factor; break;
3656
3908
  case AL_MAX_DISTANCE: *values = src->max_distance; break;
3657
- case AL_PITCH: *values = src->pitch; break;
3909
+ case AL_PITCH: source_set_pitch(ctx, src, *values); break;
3658
3910
  case AL_CONE_INNER_ANGLE: *values = src->cone_inner_angle; break;
3659
3911
  case AL_CONE_OUTER_ANGLE: *values = src->cone_outer_angle; break;
3660
3912
  case AL_CONE_OUTER_GAIN: *values = src->cone_outer_gain; break;
@@ -3955,7 +4207,7 @@ static float source_get_offset(ALsource *src, ALenum param)
3955
4207
  int proc_buf = SDL_AtomicGet(&src->buffer_queue_processed.num_items);
3956
4208
  offset = (proc_buf * item->buffer->len + src->offset);
3957
4209
  }
3958
- } else {
4210
+ } else if (src->buffer) {
3959
4211
  framesize = (int) (src->buffer->channels * sizeof (float));
3960
4212
  freq = (int) src->buffer->frequency;
3961
4213
  offset = src->offset;
@@ -4482,12 +4734,14 @@ static void _alBufferData(const ALuint name, const ALenum alfmt, const ALvoid *d
4482
4734
  if (rc == 1) { /* conversion necessary */
4483
4735
  rc = SDL_ConvertAudio(&sdlcvt);
4484
4736
  SDL_assert(rc == 0); /* this shouldn't fail. */
4737
+ #if 0 /* !!! FIXME: need realloc_simd_aligned. */
4485
4738
  if (sdlcvt.len_cvt < (size * sdlcvt.len_mult)) { /* maybe shrink buffer */
4486
4739
  void *ptr = SDL_realloc(sdlcvt.buf, sdlcvt.len_cvt);
4487
4740
  if (ptr) {
4488
4741
  sdlcvt.buf = (Uint8 *) ptr;
4489
4742
  }
4490
4743
  }
4744
+ #endif
4491
4745
  }
4492
4746
 
4493
4747
  free_simd_aligned((void *) buffer->data); /* nuke any previous data. */