1 //////////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (c) 2004-2021 musikcube team
4 //
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 //
10 //    * Redistributions of source code must retain the above copyright notice,
11 //      this list of conditions and the following disclaimer.
12 //
13 //    * Redistributions in binary form must reproduce the above copyright
14 //      notice, this list of conditions and the following disclaimer in the
15 //      documentation and/or other materials provided with the distribution.
16 //
17 //    * Neither the name of the author nor the names of other contributors may
18 //      be used to endorse or promote products derived from this software
19 //      without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 // POSSIBILITY OF SUCH DAMAGE.
32 //
33 //////////////////////////////////////////////////////////////////////////////
34 
35 #include "pch.hpp"
36 
37 #include <musikcore/audio/Buffer.h>
38 
39 #ifdef WIN32
40     #define CopyFloat(dst, src, num) CopyMemory(dst, src, (num) * sizeof(float))
41 #else
42     #define CopyFloat(dst, src, num) memcpy((float*) dst, (float*)src, (num) * sizeof(float))
43 #endif
44 
45 using namespace musik::core::audio;
46 
Buffer(Flags flags)47 Buffer::Buffer(Flags flags) noexcept
48 : buffer(nullptr)
49 , samples(0)
50 , internalBufferSize(0)
51 , sampleRate(44100)
52 , channels(2)
53 , flags(flags)
54 , position(0) {
55 }
56 
Buffer(float * buffer,int samples)57 Buffer::Buffer(float* buffer, int samples) noexcept
58 : buffer(buffer)
59 , samples(samples)
60 , internalBufferSize(samples)
61 , sampleRate(44100)
62 , channels(2)
63 , flags(ImmutableSize | NoDelete)
64 , position(0) {
65 }
66 
~Buffer()67 Buffer::~Buffer() {
68     if ((flags & NoDelete) == 0) {
69         delete[] this->buffer;
70     }
71 }
72 
SampleRate() const73 long Buffer::SampleRate() const noexcept { /* hertz */
74     return this->sampleRate;
75 }
76 
SetSampleRate(long sampleRate)77 void Buffer::SetSampleRate(long sampleRate) noexcept { /* hertz */
78     this->sampleRate = sampleRate;
79 }
80 
Channels() const81 int Buffer::Channels() const noexcept {
82     return this->channels;
83 }
84 
SetChannels(int channels)85 void Buffer::SetChannels(int channels) noexcept {
86     this->channels = channels;
87 }
88 
BufferPointer() const89 float* Buffer::BufferPointer() const noexcept {
90     return this->buffer;
91 }
92 
Samples() const93 long Buffer::Samples() const noexcept {
94     return this->samples;
95 }
96 
SetSamples(long samples)97 void Buffer::SetSamples(long samples) {
98     this->samples = samples;
99     this->ResizeBuffer();
100 }
101 
CopyFormat(Buffer * fromBuffer)102 void Buffer::CopyFormat(Buffer* fromBuffer) noexcept {
103     if (fromBuffer) {
104         this->channels = fromBuffer->Channels();
105         this->sampleRate = fromBuffer->SampleRate();
106     }
107 }
108 
ResizeBuffer()109 void Buffer::ResizeBuffer() {
110     if (this->samples > this->internalBufferSize) {
111         if (flags & ImmutableSize && this->internalBufferSize > 0) {
112             throw std::runtime_error("buffer cannot be resized");
113         }
114 
115         delete[] this->buffer;
116         this->buffer = new float[this->samples];
117         this->internalBufferSize = this->samples;
118     }
119 }
120 
121 /* logical bytes; backing store may be be larger */
Bytes() const122 long Buffer::Bytes() const noexcept {
123     return sizeof(float) * this->samples;
124 }
125 
Position() const126 double Buffer::Position() const noexcept {
127     return this->position;
128 }
129 
SetPosition(double position)130 void Buffer::SetPosition(double position) noexcept {
131     this->position = position;
132 }
133 
Copy(float const * buffer,long samples,long offset)134 void Buffer::Copy(float const* buffer, long samples, long offset) {
135     const long length = offset + samples;
136     if (length > this->internalBufferSize) {
137         float *newBuffer = new float[length];
138         CopyFloat(newBuffer, this->buffer, this->internalBufferSize);
139         CopyFloat(newBuffer + offset, buffer, samples);
140         delete[] this->buffer;
141         this->buffer = newBuffer;
142         this->internalBufferSize = length;
143     }
144     else {
145         CopyFloat(this->buffer + offset, buffer, samples);
146     }
147 
148     this->samples = std::max(this->samples, length);
149 }