1/**
2 * Copyright (c) 2006-2023 LOVE Development Team
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute it
10 * freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 * 2. Altered source versions must be plainly marked as such, and must not be
17 * misrepresented as being the original software.
18 * 3. This notice may not be removed or altered from any source distribution.
19 **/
20
21#include "SoundData.h"
22
23// C
24#include <cstdlib>
25#include <cstring>
26
27// C++
28#include <limits>
29#include <iostream>
30#include <vector>
31
32namespace love
33{
34namespace sound
35{
36
37love::Type SoundData::type("SoundData", &Data::type);
38
39SoundData::SoundData(Decoder *decoder)
40 : data(0)
41 , size(0)
42 , sampleRate(Decoder::DEFAULT_SAMPLE_RATE)
43 , bitDepth(0)
44 , channels(0)
45{
46 if (decoder->getBitDepth() != 8 && decoder->getBitDepth() != 16)
47 throw love::Exception("Invalid bit depth: %d", decoder->getBitDepth());
48
49 size_t bufferSize = 524288; // 0x80000
50 int decoded = decoder->decode();
51
52 while (decoded > 0)
53 {
54 // Expand or allocate buffer. Note that realloc may move
55 // memory to other locations.
56 if (!data || bufferSize < size + decoded)
57 {
58 while (bufferSize < size + decoded)
59 bufferSize <<= 1;
60 data = (uint8 *) realloc(data, bufferSize);
61 }
62
63 if (!data)
64 throw love::Exception("Not enough memory.");
65
66 // Copy memory into new part of memory.
67 memcpy(data + size, decoder->getBuffer(), decoded);
68
69 // Overflow check.
70 if (size > std::numeric_limits<size_t>::max() - decoded)
71 {
72 free(data);
73 throw love::Exception("Not enough memory.");
74 }
75
76 // Keep this up to date.
77 size += decoded;
78
79 decoded = decoder->decode();
80 }
81
82 // Shrink buffer if necessary.
83 if (data && bufferSize > size)
84 data = (uint8 *) realloc(data, size);
85
86 channels = decoder->getChannelCount();
87 bitDepth = decoder->getBitDepth();
88 sampleRate = decoder->getSampleRate();
89}
90
91SoundData::SoundData(int samples, int sampleRate, int bitDepth, int channels)
92 : data(0)
93 , size(0)
94 , sampleRate(0)
95 , bitDepth(0)
96 , channels(0)
97{
98 load(samples, sampleRate, bitDepth, channels);
99}
100
101SoundData::SoundData(void *d, int samples, int sampleRate, int bitDepth, int channels)
102 : data(0)
103 , size(0)
104 , sampleRate(0)
105 , bitDepth(0)
106 , channels(0)
107{
108 load(samples, sampleRate, bitDepth, channels, d);
109}
110
111SoundData::SoundData(const SoundData &c)
112 : data(0)
113 , size(0)
114 , sampleRate(0)
115 , bitDepth(0)
116 , channels(0)
117{
118 load(c.getSampleCount(), c.getSampleRate(), c.getBitDepth(), c.getChannelCount(), c.getData());
119}
120
121SoundData::~SoundData()
122{
123 if (data != 0)
124 free(data);
125}
126
127SoundData *SoundData::clone() const
128{
129 return new SoundData(*this);
130}
131
132void SoundData::load(int samples, int sampleRate, int bitDepth, int channels, void *newData)
133{
134 if (samples <= 0)
135 throw love::Exception("Invalid sample count: %d", samples);
136
137 if (sampleRate <= 0)
138 throw love::Exception("Invalid sample rate: %d", sampleRate);
139
140 if (bitDepth != 8 && bitDepth != 16)
141 throw love::Exception("Invalid bit depth: %d", bitDepth);
142
143 if (channels <= 0)
144 throw love::Exception("Invalid channel count: %d", channels);
145
146 if (data != 0)
147 {
148 free(data);
149 data = 0;
150 }
151
152 size = samples * (bitDepth / 8) * channels;
153 this->sampleRate = sampleRate;
154 this->bitDepth = bitDepth;
155 this->channels = channels;
156
157 double realsize = samples;
158 realsize *= (bitDepth / 8) * channels;
159 if (realsize > std::numeric_limits<size_t>::max())
160 throw love::Exception("Data is too big!");
161
162 data = (uint8 *) malloc(size);
163 if (!data)
164 throw love::Exception("Not enough memory.");
165
166 if (newData)
167 memcpy(data, newData, size);
168 else
169 memset(data, bitDepth == 8 ? 128 : 0, size);
170}
171
172void *SoundData::getData() const
173{
174 return (void *)data;
175}
176
177size_t SoundData::getSize() const
178{
179 return size;
180}
181
182int SoundData::getChannelCount() const
183{
184 return channels;
185}
186
187int SoundData::getBitDepth() const
188{
189 return bitDepth;
190}
191
192int SoundData::getSampleRate() const
193{
194 return sampleRate;
195}
196
197int SoundData::getSampleCount() const
198{
199 return (int) ((size/channels)/(bitDepth/8));
200}
201
202float SoundData::getDuration() const
203{
204 return float(size) / (channels*sampleRate*bitDepth/8);
205}
206
207void SoundData::setSample(int i, float sample)
208{
209 // Check range.
210 if (i < 0 || (size_t) i >= size/(bitDepth/8))
211 throw love::Exception("Attempt to set out-of-range sample!");
212
213 if (bitDepth == 16)
214 {
215 // 16-bit sample values are signed.
216 int16 *s = (int16 *) data;
217 s[i] = (int16) (sample * (float) LOVE_INT16_MAX);
218 }
219 else
220 {
221 // 8-bit sample values are unsigned internally.
222 data[i] = (uint8) ((sample * 127.0f) + 128.0f);
223 }
224}
225
226void SoundData::setSample(int i, int channel, float sample)
227{
228 if (channel < 1 || channel > channels)
229 throw love::Exception("Attempt to set sample from out-of-range channel!");
230
231 return setSample(i * channels + (channel - 1), sample);
232}
233
234float SoundData::getSample(int i) const
235{
236 // Check range.
237 if (i < 0 || (size_t) i >= size/(bitDepth/8))
238 throw love::Exception("Attempt to get out-of-range sample!");
239
240 if (bitDepth == 16)
241 {
242 // 16-bit sample values are signed.
243 int16 *s = (int16 *) data;
244 return (float) s[i] / (float) LOVE_INT16_MAX;
245 }
246 else
247 {
248 // 8-bit sample values are unsigned internally.
249 return ((float) data[i] - 128.0f) / 127.0f;
250 }
251}
252
253float SoundData::getSample(int i, int channel) const
254{
255 if (channel < 1 || channel > channels)
256 throw love::Exception("Attempt to get sample from out-of-range channel!");
257
258 return getSample(i * channels + (channel - 1));
259}
260
261} // sound
262} // love
263