1 /*
2 Copyright (c) 2009-2010 Tero Lindeman (kometbomb)
3
4 Permission is hereby granted, free of charge, to any person
5 obtaining a copy of this software and associated documentation
6 files (the "Software"), to deal in the Software without
7 restriction, including without limitation the rights to use,
8 copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the
10 Software is furnished to do so, subject to the following
11 conditions:
12
13 The above copyright notice and this permission notice shall be
14 included in all copies or substantial portions of the Software.
15
16 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 OTHER DEALINGS IN THE SOFTWARE.
24 */
25
26 #include "cydwave.h"
27 #include "cyddefs.h"
28 #include "macros.h"
29
30 #ifndef LOWRESWAVETABLE
31 typedef Sint64 WaveAccSigned;
32 #else
33 typedef Sint32 WaveAccSigned;
34 #endif
35
36 #ifndef CYD_DISABLE_WAVETABLE
cyd_wave_get_sample_no_interpolation(const CydWavetableEntry * entry,CydWaveAcc wave_acc,int direction)37 static Sint32 cyd_wave_get_sample_no_interpolation(const CydWavetableEntry *entry, CydWaveAcc wave_acc, int direction)
38 {
39 if (entry->data)
40 {
41 return entry->data[wave_acc / WAVETABLE_RESOLUTION];
42 }
43 else
44 return 0;
45 }
46
47
cyd_wave_get_sample_linear(const CydWavetableEntry * entry,CydWaveAcc wave_acc,int direction)48 static Sint32 cyd_wave_get_sample_linear(const CydWavetableEntry *entry, CydWaveAcc wave_acc, int direction)
49 {
50 if (entry->data)
51 {
52 if (direction == 0)
53 {
54 int a = wave_acc / WAVETABLE_RESOLUTION;
55 int b = a + 1;
56
57 if (a >= entry->samples || a < 0)
58 return 0;
59
60 if ((entry->flags & CYD_WAVE_LOOP) && b >= entry->loop_end)
61 {
62 if (!(entry->flags & CYD_WAVE_PINGPONG))
63 b = b - entry->loop_end + entry->loop_begin;
64 else
65 b = entry->loop_end - (b - entry->loop_end);
66 }
67
68 if (b >= entry->samples)
69 return entry->data[a];
70 else
71 return entry->data[a] + (entry->data[b] - entry->data[a]) * ((CydWaveAccSigned)wave_acc % WAVETABLE_RESOLUTION) / WAVETABLE_RESOLUTION;
72 }
73 else
74 {
75 int a = wave_acc / WAVETABLE_RESOLUTION;
76 int b = a - 1;
77
78 if (a >= entry->samples || a < 0)
79 return 0;
80
81 if ((entry->flags & CYD_WAVE_LOOP) && b < (Sint32)entry->loop_begin)
82 {
83 if (!(entry->flags & CYD_WAVE_PINGPONG))
84 b = b - entry->loop_begin + entry->loop_end;
85 else
86 b = entry->loop_begin - (b - entry->loop_begin);
87 }
88
89 if (b < 0)
90 return entry->data[a];
91 else
92 return entry->data[a] + (entry->data[b] - entry->data[a]) * (WAVETABLE_RESOLUTION - ((CydWaveAccSigned)wave_acc % WAVETABLE_RESOLUTION)) / WAVETABLE_RESOLUTION;
93 }
94 }
95 else
96 return 0;
97 }
98 #endif // CYD_DISABLE_WAVETABLE
99
100
cyd_wave_get_sample(const CydWaveState * state,const CydWavetableEntry * wave_entry,CydWaveAcc acc)101 Sint32 cyd_wave_get_sample(const CydWaveState *state, const CydWavetableEntry *wave_entry, CydWaveAcc acc)
102 {
103 #ifndef CYD_DISABLE_WAVETABLE
104 if (wave_entry->flags & CYD_WAVE_NO_INTERPOLATION)
105 {
106 return cyd_wave_get_sample_no_interpolation(wave_entry, acc, state->direction);
107 }
108 else
109 {
110 return cyd_wave_get_sample_linear(wave_entry, acc, state->direction);
111 }
112
113 #else
114 return 0;
115 #endif // CYD_DISABLE_WAVETABLE
116 }
117
118
cyd_wave_cycle(CydWaveState * wave,const CydWavetableEntry * wave_entry)119 void cyd_wave_cycle(CydWaveState *wave, const CydWavetableEntry *wave_entry)
120 {
121 #ifndef CYD_DISABLE_WAVETABLE
122
123 if (wave_entry && wave->playing)
124 {
125 if (wave->direction == 0)
126 {
127 wave->acc += wave->frequency;
128
129 if ((wave_entry->flags & CYD_WAVE_LOOP) && wave_entry->loop_end != wave_entry->loop_begin)
130 {
131 if (wave->acc / WAVETABLE_RESOLUTION >= (Uint64)wave_entry->loop_end)
132 {
133 if (wave_entry->flags & CYD_WAVE_PINGPONG)
134 {
135 wave->acc = (Uint64)wave_entry->loop_end * WAVETABLE_RESOLUTION - (wave->acc - (Uint64)wave_entry->loop_end * WAVETABLE_RESOLUTION);
136 wave->direction = 1;
137 }
138 else
139 {
140 wave->acc = wave->acc - (Uint64)wave_entry->loop_end * WAVETABLE_RESOLUTION + (Uint64)wave_entry->loop_begin * WAVETABLE_RESOLUTION;
141 }
142 }
143 }
144 else
145 {
146 if (wave->acc / WAVETABLE_RESOLUTION >= (Uint64)wave_entry->samples)
147 {
148 // stop playback
149 wave->playing = false;
150 }
151 }
152 }
153 else
154 {
155 wave->acc -= wave->frequency;
156
157 if ((wave_entry->flags & CYD_WAVE_LOOP) && wave_entry->loop_end != wave_entry->loop_begin)
158 {
159 if ((WaveAccSigned)wave->acc / WAVETABLE_RESOLUTION < (WaveAccSigned)wave_entry->loop_begin)
160 {
161 if (wave_entry->flags & CYD_WAVE_PINGPONG)
162 {
163 wave->acc = (WaveAccSigned)wave_entry->loop_begin * WAVETABLE_RESOLUTION - ((WaveAccSigned)wave->acc - (WaveAccSigned)wave_entry->loop_begin * WAVETABLE_RESOLUTION);
164 wave->direction = 0;
165 }
166 else
167 {
168 wave->acc = wave->acc - (Uint64)wave_entry->loop_begin * WAVETABLE_RESOLUTION + (Uint64)wave_entry->loop_end * WAVETABLE_RESOLUTION;
169 }
170 }
171 }
172 else
173 {
174 if ((WaveAccSigned)wave->acc < 0)
175 {
176 // stop playback
177 wave->playing = false;
178 }
179 }
180 }
181 }
182
183 #endif // CYD_DISABLE_WAVETABLE
184 }
185