gosu 1.4.1 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) 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/ext/gosu/extconf.rb +6 -3
  42. data/include/Gosu/Buttons.hpp +103 -103
  43. data/include/Gosu/Directories.hpp +31 -24
  44. data/include/Gosu/Font.hpp +4 -2
  45. data/include/Gosu/Gosu.hpp +5 -8
  46. data/include/Gosu/IO.hpp +0 -3
  47. data/include/Gosu/Input.hpp +7 -1
  48. data/include/Gosu/Math.hpp +0 -3
  49. data/include/Gosu/TextInput.hpp +3 -3
  50. data/include/Gosu/Timing.hpp +3 -6
  51. data/include/Gosu/Version.hpp +1 -1
  52. data/include/Gosu/Window.hpp +3 -2
  53. data/rdoc/gosu.rb +16 -2
  54. data/src/Audio.cpp +2 -2
  55. data/src/AudioFileAudioToolbox.cpp +1 -1
  56. data/src/AudioFileSDLSound.cpp +1 -1
  57. data/src/AudioImpl.cpp +0 -7
  58. data/src/AudioImpl.hpp +1 -3
  59. data/src/BitmapIO.cpp +23 -2
  60. data/src/BlockAllocator.cpp +1 -1
  61. data/src/DirectoriesApple.cpp +25 -24
  62. data/src/DirectoriesUnix.cpp +14 -12
  63. data/src/DirectoriesWin.cpp +26 -30
  64. data/src/FileUnix.cpp +1 -1
  65. data/src/FileWin.cpp +1 -1
  66. data/src/Font.cpp +13 -3
  67. data/src/Graphics.cpp +1 -1
  68. data/src/Image.cpp +10 -15
  69. data/src/Input.cpp +16 -1
  70. data/src/InputUIKit.cpp +1 -1
  71. data/src/Macro.cpp +1 -1
  72. data/src/RubyGosu.cxx +76 -34
  73. data/src/TextInput.cpp +1 -1
  74. data/src/TimingApple.cpp +2 -2
  75. data/src/TimingUnix.cpp +3 -7
  76. data/src/TimingWin.cpp +1 -2
  77. data/src/TrueTypeFont.cpp +1 -1
  78. data/src/Window.cpp +5 -4
  79. data/src/WindowUIKit.cpp +1 -1
  80. metadata +3 -3
@@ -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. */