Skip to content

Commit d0622ac

Browse files
author
Nathan Ho
authored
Merge pull request #7 from cianoc/master
Added C++ version of MySaw
2 parents 55af892 + 529ee52 commit d0622ac

File tree

6 files changed

+380
-0
lines changed

6 files changed

+380
-0
lines changed

02b-MySaw/CMakeLists.txt

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
set(FILENAME "MySaw2.cpp") #specify the .cpp file here
2+
cmake_minimum_required (VERSION 2.8)
3+
get_filename_component(PROJECT ${FILENAME} NAME_WE) #automatically sets project name from the filename
4+
# set(PROJECT "my_name") #alternatively set project name manually
5+
message(STATUS "Project name is ${PROJECT}")
6+
project (${PROJECT})
7+
8+
include_directories(${SC_PATH}/include/plugin_interface)
9+
include_directories(${SC_PATH}/include/common)
10+
include_directories(${SC_PATH}/common)
11+
12+
set(CMAKE_SHARED_MODULE_PREFIX "")
13+
if(APPLE OR WIN32)
14+
set(CMAKE_SHARED_MODULE_SUFFIX ".scx")
15+
endif()
16+
17+
option(SUPERNOVA "Build plugins for supernova" OFF)
18+
if (SUPERNOVA)
19+
include_directories(${SC_PATH}/external_libraries/nova-tt)
20+
# actually just boost.atomic
21+
include_directories(${SC_PATH}/external_libraries/boost)
22+
include_directories(${SC_PATH}/external_libraries/boost_lockfree)
23+
include_directories(${SC_PATH}/external_libraries/boost-lockfree)
24+
endif()
25+
26+
option(CPP11 "Build with c++11." ON)
27+
28+
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
29+
set(CMAKE_COMPILER_IS_CLANG 1)
30+
endif()
31+
32+
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANG)
33+
add_definitions(-fvisibility=hidden)
34+
35+
include (CheckCCompilerFlag)
36+
include (CheckCXXCompilerFlag)
37+
38+
CHECK_C_COMPILER_FLAG(-msse HAS_SSE)
39+
CHECK_CXX_COMPILER_FLAG(-msse HAS_CXX_SSE)
40+
41+
if (HAS_SSE)
42+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse")
43+
endif()
44+
if (HAS_CXX_SSE)
45+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse")
46+
endif()
47+
48+
CHECK_C_COMPILER_FLAG(-msse2 HAS_SSE2)
49+
CHECK_CXX_COMPILER_FLAG(-msse2 HAS_CXX_SSE2)
50+
51+
if (HAS_SSE2)
52+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse2")
53+
endif()
54+
if (HAS_CXX_SSE2)
55+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse2")
56+
endif()
57+
58+
CHECK_C_COMPILER_FLAG(-mfpmath=sse HAS_FPMATH_SSE)
59+
CHECK_CXX_COMPILER_FLAG(-mfpmath=sse HAS_CXX_FPMATH_SSE)
60+
61+
if (HAS_FPMATH_SSE)
62+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfpmath=sse")
63+
endif()
64+
if (HAS_CXX_FPMATH_SSE)
65+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mfpmath=sse")
66+
endif()
67+
68+
if(NATIVE)
69+
add_definitions(-march=native)
70+
endif()
71+
72+
if(CPP11)
73+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
74+
if(CMAKE_COMPILER_IS_CLANG)
75+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
76+
endif()
77+
endif()
78+
endif()
79+
if(MINGW)
80+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mstackrealign")
81+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mstackrealign")
82+
endif()
83+
84+
add_library(${PROJECT} MODULE ${FILENAME})
85+
if(SUPERNOVA)
86+
add_library(${PROJECT}_supernova MODULE ${FILENAME})
87+
set_property(TARGET ${PROJECT}_supernova
88+
PROPERTY COMPILE_DEFINITIONS SUPERNOVA)
89+
endif()

02b-MySaw/MySaw.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include "SC_PlugIn.hpp"
2+
3+
// InterfaceTable contains pointers to functions in the host (server).
4+
static InterfaceTable *ft;
5+
6+
// declare struct to hold unit generator state
7+
struct MySaw : public SCUnit{
8+
9+
// Constructor usually does 3 things.
10+
// 1. set the calculation function.
11+
// 2. initialize the unit generator state variables.
12+
// 3. calculate one sample of output.
13+
public:
14+
MySaw() {
15+
// 1. set the calculation function.
16+
if (isAudioRateIn(0)) {
17+
// if the frequency argument is audio rate
18+
set_calc_function<MySaw,&MySaw::next_a>();
19+
} else {
20+
// if thene frequency argument is control rate (or a scalar).
21+
set_calc_function<MySaw,&MySaw::next_k>();
22+
}
23+
24+
// 2. initialize the unit generator state variables.
25+
// initialize a constant for multiplying the frequency
26+
mFreqMul = 2.0 * sampleDur();
27+
// get initial phase of oscillator
28+
mPhase = in0(1);
29+
30+
// 3. calculate one sample of output.
31+
if (isAudioRateIn(0)) {
32+
next_a(1);
33+
} else {
34+
next_k(1);
35+
}
36+
37+
}
38+
39+
private:
40+
double mPhase; // phase of the oscillator, from -1 to 1.
41+
float mFreqMul; // a constant for multiplying frequency
42+
43+
//////////////////////////////////////////////////////////////////
44+
45+
// The calculation function executes once per control period
46+
// which is typically 64 samples.
47+
48+
// calculation function for an audio rate frequency argument
49+
void next_a(int inNumSamples)
50+
{
51+
// get the pointer to the output buffer
52+
float *outBuf = out(0);
53+
54+
// get the pointer to the input buffer
55+
const float *freq = in(0);
56+
57+
// get phase and freqmul constant from struct and store it in a
58+
// local variable.
59+
// The optimizer will cause them to be loaded it into a register.
60+
float freqmul = mFreqMul;
61+
double phase = mPhase;
62+
63+
// perform a loop for the number of samples in the control period.
64+
// If this unit is audio rate then inNumSamples will be 64 or whatever
65+
// the block size is. If this unit is control rate then inNumSamples will
66+
// be 1.
67+
for (int i=0; i < inNumSamples; ++i)
68+
{
69+
// out must be written last for in place operation
70+
float z = phase;
71+
phase += freq[i] * freqmul;
72+
73+
// these if statements wrap the phase a +1 or -1.
74+
if (phase >= 1.f) phase -= 2.f;
75+
else if (phase <= -1.f) phase += 2.f;
76+
77+
// write the output
78+
outBuf[i] = z;
79+
}
80+
81+
// store the phase back to the struct
82+
mPhase = phase;
83+
}
84+
85+
//////////////////////////////////////////////////////////////////
86+
87+
// calculation function for a control rate frequency argument
88+
void next_k(int inNumSamples)
89+
{
90+
// get the pointer to the output buffer
91+
float *outBuf = out(0);
92+
93+
// freq is control rate, so calculate it once.
94+
float freq = in0(0) * mFreqMul;
95+
96+
// get phase from struct and store it in a local variable.
97+
// The optimizer will cause it to be loaded it into a register.
98+
double phase = mPhase;
99+
100+
// since the frequency is not changing then we can simplify the loops
101+
// by separating the cases of positive or negative frequencies.
102+
// This will make them run faster because there is less code inside the loop.
103+
if (freq >= 0.f) {
104+
// positive frequencies
105+
for (int i=0; i < inNumSamples; ++i)
106+
{
107+
outBuf[i] = phase;
108+
phase += freq;
109+
if (phase >= 1.f) phase -= 2.f;
110+
}
111+
} else {
112+
// negative frequencies
113+
for (int i=0; i < inNumSamples; ++i)
114+
{
115+
outBuf[i] = phase;
116+
phase += freq;
117+
if (phase <= -1.f) phase += 2.f;
118+
}
119+
}
120+
121+
// store the phase back to the struct
122+
mPhase = phase;
123+
}
124+
};
125+
126+
// the entry point is called by the host when the plug-in is loaded
127+
PluginLoad(MySawUGens)
128+
{
129+
// InterfaceTable *inTable implicitly given as argument to the load function
130+
ft = inTable; // store pointer to InterfaceTable
131+
132+
// registerUnit takes the place of the Define*Unit functions. It automatically checks for the presence of a
133+
// destructor function.
134+
// However, it does not seem to be possible to disable buffer aliasing with the C++ header.
135+
registerUnit<MySaw>(ft, "MySaw");
136+
}

02b-MySaw/MySaw.sc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// without mul and add.
2+
MySaw : UGen {
3+
*ar { arg freq = 440.0, iphase = 0.0;
4+
^this.multiNew('audio', freq, iphase)
5+
}
6+
*kr { arg freq = 440.0, iphase = 0.0;
7+
^this.multiNew('control', freq, iphase)
8+
}
9+
}

02b-MySaw/MySaw2.cpp

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#include "SC_PlugIn.hpp"
2+
3+
// InterfaceTable contains pointers to functions in the host (server).
4+
static InterfaceTable *ft;
5+
6+
// declare struct to hold unit generator state
7+
struct MySaw2 : public SCUnit{
8+
9+
// Constructor usually does 3 things.
10+
// 1. set the calculation function.
11+
// 2. initialize the unit generator state variables.
12+
// 3. calculate one sample of output.
13+
public:
14+
MySaw2() {
15+
// 1. set the calculation function.
16+
if (isAudioRateIn(0)) {
17+
// if the frequency argument is audio rate
18+
set_calc_function<MySaw2,&MySaw2::next_a>();
19+
} else {
20+
// if thene frequency argument is control rate (or a scalar).
21+
set_calc_function<MySaw2,&MySaw2::next_k>();
22+
}
23+
24+
// 2. initialize the unit generator state variables.
25+
// initialize a constant for multiplying the frequency
26+
mFreqMul = 2.0 * sampleDur();
27+
// get initial phase of oscillator
28+
mPhase = in0(1);
29+
30+
// 3. calculate one sample of output.
31+
if (isAudioRateIn(0)) {
32+
next_a(1);
33+
} else {
34+
next_k(1);
35+
}
36+
37+
}
38+
39+
private:
40+
double mPhase; // phase of the oscillator, from -1 to 1.
41+
float mFreqMul; // a constant for multiplying frequency
42+
43+
//////////////////////////////////////////////////////////////////
44+
45+
// The calculation function executes once per control period
46+
// which is typically 64 samples.
47+
48+
// calculation function for an audio rate frequency argument
49+
void next_a(int inNumSamples)
50+
{
51+
// get the pointer to the output buffer
52+
float *outBuf = out(0);
53+
54+
// get the pointer to the input buffer
55+
const float *freq = in(0);
56+
57+
// get phase and freqmul constant from struct and store it in a
58+
// local variable.
59+
// The optimizer will cause them to be loaded it into a register.
60+
float freqmul = mFreqMul;
61+
double phase = mPhase;
62+
63+
// perform a loop for the number of samples in the control period.
64+
// If this unit is audio rate then inNumSamples will be 64 or whatever
65+
// the block size is. If this unit is control rate then inNumSamples will
66+
// be 1.
67+
for (int i=0; i < inNumSamples; ++i)
68+
{
69+
// out must be written last for in place operation
70+
float z = phase;
71+
phase += freq[i] * freqmul;
72+
73+
// these if statements wrap the phase a +1 or -1.
74+
if (phase >= 1.f) phase -= 2.f;
75+
else if (phase <= -1.f) phase += 2.f;
76+
77+
// write the output
78+
outBuf[i] = z;
79+
}
80+
81+
// store the phase back to the struct
82+
mPhase = phase;
83+
}
84+
85+
//////////////////////////////////////////////////////////////////
86+
87+
// calculation function for a control rate frequency argument
88+
void next_k(int inNumSamples)
89+
{
90+
// get the pointer to the output buffer
91+
float *outBuf = out(0);
92+
93+
// freq is control rate, so calculate it once.
94+
float freq = in0(0) * mFreqMul;
95+
96+
// get phase from struct and store it in a local variable.
97+
// The optimizer will cause it to be loaded it into a register.
98+
double phase = mPhase;
99+
100+
// since the frequency is not changing then we can simplify the loops
101+
// by separating the cases of positive or negative frequencies.
102+
// This will make them run faster because there is less code inside the loop.
103+
if (freq >= 0.f) {
104+
// positive frequencies
105+
for (int i=0; i < inNumSamples; ++i)
106+
{
107+
outBuf[i] = phase;
108+
phase += freq;
109+
if (phase >= 1.f) phase -= 2.f;
110+
}
111+
} else {
112+
// negative frequencies
113+
for (int i=0; i < inNumSamples; ++i)
114+
{
115+
outBuf[i] = phase;
116+
phase += freq;
117+
if (phase <= -1.f) phase += 2.f;
118+
}
119+
}
120+
121+
// store the phase back to the struct
122+
mPhase = phase;
123+
}
124+
};
125+
126+
// the entry point is called by the host when the plug-in is loaded
127+
PluginLoad(MySaw2UGens)
128+
{
129+
// InterfaceTable *inTable implicitly given as argument to the load function
130+
ft = inTable; // store pointer to InterfaceTable
131+
132+
// registerUnit takes the place of the Define*Unit functions. It automatically checks for the presence of a
133+
// destructor function.
134+
// However, it does not seem to be possible to disable buffer aliasing with the C++ header.
135+
registerUnit<MySaw2>(ft, "MySaw2");
136+
}

02b-MySaw/MySaw2.sc

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// without mul and add.
2+
MySaw2 : UGen {
3+
*ar { arg freq = 440.0, iphase = 0.0;
4+
^this.multiNew('audio', freq, iphase)
5+
}
6+
*kr { arg freq = 440.0, iphase = 0.0;
7+
^this.multiNew('control', freq, iphase)
8+
}
9+
}

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Beyond this repository, the reader is encouraged to look at [sc3-plugins](https:
1313
- 01a-BoringMixer -- minimal example of a plugin
1414
- 01b-BoringMixer -- using a newer C++ wrapper
1515
- 02-MySaw -- introduces multiple calculation functions and state variables
16+
- 02b-MySaw -- using a newer C++ wrapper
1617
- 03-AnalogEcho -- introduces memory allocation and cubic interpolation
1718

1819
## Compiling

0 commit comments

Comments
 (0)