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