1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #pragma once
22
23 #include <stdint.h>
24
25 typedef struct SNDFILE_tag SNDFILE;
26
27 #ifdef SUPERNOVA
28
29 # include <atomic>
30 # include <cassert>
31
32 # ifdef __SSE2__
33 # include <emmintrin.h>
34 # endif
35
36
37 class rw_spinlock {
38 static const uint32_t unlocked_state = 0;
39 static const uint32_t locked_state = 0x80000000;
40 static const uint32_t reader_mask = 0x7fffffff;
41
42 # ifdef __SSE2__
pause()43 static inline void pause() { _mm_pause(); }
44 # else
pause()45 static inline void pause() {}
46 # endif
47
48 public:
49 struct unique_lock {
unique_lockunique_lock50 explicit unique_lock(rw_spinlock& sl): sl_(sl) { sl_.lock(); }
~unique_lockunique_lock51 ~unique_lock() { sl_.unlock(); }
52
53 private:
54 rw_spinlock& sl_;
55 };
56
57 typedef unique_lock unique_lock;
58
59 struct shared_lock {
shared_lockshared_lock60 explicit shared_lock(rw_spinlock& sl): sl_(sl) { sl_.lock_shared(); }
~shared_lockshared_lock61 ~shared_lock() { sl_.unlock_shared(); }
62
63 private:
64 rw_spinlock& sl_;
65 };
66
67 rw_spinlock() = default;
68 rw_spinlock(rw_spinlock const& rhs) = delete;
69 rw_spinlock& operator=(rw_spinlock const& rhs) = delete;
70 rw_spinlock(rw_spinlock&& rhs) = delete;
71
~rw_spinlock()72 ~rw_spinlock() { assert(state == unlocked_state); }
73
lock()74 void lock() {
75 for (;;) {
76 while (state.load(std::memory_order_relaxed) != unlocked_state)
77 pause();
78
79 uint32_t expected = unlocked_state;
80 if (state.compare_exchange_weak(expected, locked_state, std::memory_order_acquire))
81 break;
82 }
83 }
84
try_lock()85 bool try_lock() {
86 uint32_t expected = unlocked_state;
87 if (state.compare_exchange_strong(expected, locked_state, std::memory_order_acquire))
88 return true;
89 else
90 return false;
91 }
92
unlock()93 void unlock() {
94 assert(state.load(std::memory_order_relaxed) == locked_state);
95 state.store(unlocked_state, std::memory_order_release);
96 }
97
lock_shared()98 void lock_shared() {
99 for (;;) {
100 /* with the mask, the cas will fail, locked exclusively */
101 uint32_t current_state = state.load(std::memory_order_acquire) & reader_mask;
102 const uint32_t next_state = current_state + 1;
103
104 if (state.compare_exchange_weak(current_state, next_state, std::memory_order_acquire))
105 break;
106 pause();
107 }
108 }
109
try_lock_shared()110 bool try_lock_shared() {
111 /* with the mask, the cas will fail, locked exclusively */
112 uint32_t current_state = state.load(std::memory_order_acquire) & reader_mask;
113 const uint32_t next_state = current_state + 1;
114
115 if (state.compare_exchange_strong(current_state, next_state, std::memory_order_acquire))
116 return true;
117 else
118 return false;
119 }
120
unlock_shared()121 void unlock_shared() {
122 for (;;) {
123 uint32_t current_state = state.load(std::memory_order_relaxed); /* we don't need the reader_mask */
124 const uint32_t next_state = current_state - 1;
125
126 if (state.compare_exchange_weak(current_state, uint32_t(next_state)))
127 break;
128 pause();
129 }
130 }
131
132 private:
133 std::atomic<uint32_t> state { unlocked_state };
134 };
135
136 #endif
137
138 struct SndBuf {
139 double samplerate;
140 double sampledur; // = 1/ samplerate
141 float* data;
142 int channels;
143 int samples;
144 int frames;
145 int mask; // for delay lines
146 int mask1; // for interpolating oscillators.
147 int coord; // used by fft ugens
148 SNDFILE* sndfile; // used by disk i/o
149 // SF_INFO fileinfo; // used by disk i/o
150 #ifdef SUPERNOVA
151 bool isLocal;
152 mutable rw_spinlock lock;
153 #endif
154 };
155
156 typedef struct SndBuf SndBuf;
157
158 struct SndBufUpdates {
159 int reads;
160 int writes;
161 };
162 typedef struct SndBufUpdates SndBufUpdates;
163
164 enum { coord_None, coord_Complex, coord_Polar };
165
PhaseFrac(uint32_t inPhase)166 inline float PhaseFrac(uint32_t inPhase) {
167 union {
168 uint32_t itemp;
169 float ftemp;
170 } u;
171 u.itemp = 0x3F800000 | (0x007FFF80 & ((inPhase) << 7));
172 return u.ftemp - 1.f;
173 }
174
PhaseFrac1(uint32_t inPhase)175 inline float PhaseFrac1(uint32_t inPhase) {
176 union {
177 uint32_t itemp;
178 float ftemp;
179 } u;
180 u.itemp = 0x3F800000 | (0x007FFF80 & ((inPhase) << 7));
181 return u.ftemp;
182 }
183
lookup(const float * table,int32_t phase,int32_t mask)184 inline float lookup(const float* table, int32_t phase, int32_t mask) { return table[(phase >> 16) & mask]; }
185
186
187 #define xlobits 14
188 #define xlobits1 13
189
lookupi(const float * table,uint32_t phase,uint32_t mask)190 inline float lookupi(const float* table, uint32_t phase, uint32_t mask) {
191 float frac = PhaseFrac(phase);
192 const float* tbl = table + ((phase >> 16) & mask);
193 float a = tbl[0];
194 float b = tbl[1];
195 return a + frac * (b - a);
196 }
197
lookupi2(const float * table,uint32_t phase,uint32_t mask)198 inline float lookupi2(const float* table, uint32_t phase, uint32_t mask) {
199 float frac = PhaseFrac1(phase);
200 const float* tbl = table + ((phase >> 16) & mask);
201 float a = tbl[0];
202 float b = tbl[1];
203 return a + frac * b;
204 }
205
lookupi1(const float * table0,const float * table1,uint32_t pphase,int32_t lomask)206 inline float lookupi1(const float* table0, const float* table1, uint32_t pphase, int32_t lomask) {
207 float pfrac = PhaseFrac1(pphase);
208 uint32_t index = ((pphase >> xlobits1) & (uint32_t)lomask);
209 float val1 = *(const float*)((const char*)table0 + index);
210 float val2 = *(const float*)((const char*)table1 + index);
211 return val1 + val2 * pfrac;
212 }
213
214
lininterp(float x,float a,float b)215 inline float lininterp(float x, float a, float b) { return a + x * (b - a); }
216
cubicinterp(float x,float y0,float y1,float y2,float y3)217 inline float cubicinterp(float x, float y0, float y1, float y2, float y3) {
218 // 4-point, 3rd-order Hermite (x-form)
219 float c0 = y1;
220 float c1 = 0.5f * (y2 - y0);
221 float c2 = y0 - 2.5f * y1 + 2.f * y2 - 0.5f * y3;
222 float c3 = 0.5f * (y3 - y0) + 1.5f * (y1 - y2);
223
224 return ((c3 * x + c2) * x + c1) * x + c0;
225 }
226