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.
- checksums.yaml +4 -4
- data/dependencies/SDL_sound/SDL_sound.c +21 -63
- data/dependencies/SDL_sound/SDL_sound.h +2 -2
- data/dependencies/SDL_sound/SDL_sound_aiff.c +26 -23
- data/dependencies/SDL_sound/SDL_sound_au.c +8 -8
- data/dependencies/SDL_sound/SDL_sound_coreaudio.c +4 -5
- data/dependencies/SDL_sound/SDL_sound_flac.c +28 -30
- data/dependencies/SDL_sound/SDL_sound_internal.h +4 -4
- data/dependencies/SDL_sound/SDL_sound_modplug.c +1 -1
- data/dependencies/SDL_sound/SDL_sound_mp3.c +19 -23
- data/dependencies/SDL_sound/SDL_sound_raw.c +5 -6
- data/dependencies/SDL_sound/SDL_sound_shn.c +4 -4
- data/dependencies/SDL_sound/SDL_sound_voc.c +15 -15
- data/dependencies/SDL_sound/SDL_sound_vorbis.c +14 -7
- data/dependencies/SDL_sound/SDL_sound_wav.c +17 -17
- data/dependencies/SDL_sound/dr_flac.h +10840 -4779
- data/dependencies/SDL_sound/dr_mp3.h +2793 -1004
- data/dependencies/SDL_sound/libmodplug/fastmix.c +5 -0
- data/dependencies/SDL_sound/libmodplug/load_669.c +1 -1
- data/dependencies/SDL_sound/libmodplug/load_amf.c +1 -0
- data/dependencies/SDL_sound/libmodplug/load_ams.c +38 -22
- data/dependencies/SDL_sound/libmodplug/load_it.c +18 -14
- data/dependencies/SDL_sound/libmodplug/load_mdl.c +18 -9
- data/dependencies/SDL_sound/libmodplug/load_med.c +7 -6
- data/dependencies/SDL_sound/libmodplug/load_mt2.c +36 -17
- data/dependencies/SDL_sound/libmodplug/load_okt.c +51 -24
- data/dependencies/SDL_sound/libmodplug/load_psm.c +4 -2
- data/dependencies/SDL_sound/libmodplug/load_s3m.c +4 -4
- data/dependencies/SDL_sound/libmodplug/load_ult.c +4 -3
- data/dependencies/SDL_sound/libmodplug/load_xm.c +5 -5
- data/dependencies/SDL_sound/libmodplug/snd_fx.c +8 -1
- data/dependencies/SDL_sound/libmodplug/sndfile.c +21 -4
- data/dependencies/SDL_sound/stb_vorbis.h +10 -18
- data/dependencies/mojoAL/mojoal.c +260 -6
- data/dependencies/stb/stb_image.h +208 -73
- data/dependencies/stb/stb_image_write.h +57 -23
- data/dependencies/stb/stb_truetype.h +345 -279
- data/dependencies/utf8proc/utf8proc.c +37 -18
- data/dependencies/utf8proc/utf8proc.h +17 -5
- data/dependencies/utf8proc/utf8proc_data.h +12012 -10089
- data/ext/gosu/extconf.rb +6 -3
- data/include/Gosu/Buttons.hpp +103 -103
- data/include/Gosu/Directories.hpp +31 -24
- data/include/Gosu/Font.hpp +4 -2
- data/include/Gosu/Gosu.hpp +5 -8
- data/include/Gosu/IO.hpp +0 -3
- data/include/Gosu/Input.hpp +7 -1
- data/include/Gosu/Math.hpp +0 -3
- data/include/Gosu/TextInput.hpp +3 -3
- data/include/Gosu/Timing.hpp +3 -6
- data/include/Gosu/Version.hpp +1 -1
- data/include/Gosu/Window.hpp +3 -2
- data/rdoc/gosu.rb +16 -2
- data/src/Audio.cpp +2 -2
- data/src/AudioFileAudioToolbox.cpp +1 -1
- data/src/AudioFileSDLSound.cpp +1 -1
- data/src/AudioImpl.cpp +0 -7
- data/src/AudioImpl.hpp +1 -3
- data/src/BitmapIO.cpp +23 -2
- data/src/BlockAllocator.cpp +1 -1
- data/src/DirectoriesApple.cpp +25 -24
- data/src/DirectoriesUnix.cpp +14 -12
- data/src/DirectoriesWin.cpp +26 -30
- data/src/FileUnix.cpp +1 -1
- data/src/FileWin.cpp +1 -1
- data/src/Font.cpp +13 -3
- data/src/Graphics.cpp +1 -1
- data/src/Image.cpp +10 -15
- data/src/Input.cpp +16 -1
- data/src/InputUIKit.cpp +1 -1
- data/src/Macro.cpp +1 -1
- data/src/RubyGosu.cxx +76 -34
- data/src/TextInput.cpp +1 -1
- data/src/TimingApple.cpp +2 -2
- data/src/TimingUnix.cpp +3 -7
- data/src/TimingWin.cpp +1 -2
- data/src/TrueTypeFont.cpp +1 -1
- data/src/Window.cpp +5 -4
- data/src/WindowUIKit.cpp +1 -1
- 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)
|
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
|
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 (
|
192
|
-
if (
|
193
|
-
if (
|
194
|
-
if (
|
195
|
-
if (
|
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
|
-
|
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
|
18
|
-
extern
|
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) (
|
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) :
|
975
|
-
#define temp_free(f,p) (
|
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
|
-
|
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
|
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
|
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. */
|