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