-
Notifications
You must be signed in to change notification settings - Fork 9
/
Copy pathoscilator.c
146 lines (130 loc) · 3.95 KB
/
oscilator.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/*
* JMPXRDS, an FM MPX signal generator with RDS support on
* top of Jack Audio Connection Kit - Oscilator
*
* Copyright (C) 2015 Nick Kossifidis <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "oscilator.h"
#include <stdlib.h> /* For NULL */
#include <math.h> /* For sin, cos, M_PI, fmod and signbit */
#include <string.h> /* For memset */
/***********\
* OSCILATOR *
\***********/
/*
* This is the implementation of a sine wave generator that
* produces 3 phase-synced sine waves of frequencies 19KHz,
* 38KHz and 57KHz, used to create the FM MPX signal. It can
* also produce a cosine the same way for use in SSB modulation.
*/
/**
* osc_initialize_state - Initialize the oscilator's state
*
*/
int
osc_initialize(struct osc_state *osc, uint32_t sample_rate, int type)
{
if (osc == NULL)
return -1;
memset(osc, 0, sizeof(struct osc_state));
osc->type = type;
/*
* Due to Nyquist sampling theorem, the sample rate must be at
* least twice the frequency we want to sample. To make it more
* safe, check if the max supported frequency divided by
* the sample rate is an even number (a multiple of 2)
*/
if ((MAX_FREQUENCY >= sample_rate) ||
((MAX_FREQUENCY / sample_rate) & 1))
return -3;
osc->sample_rate = sample_rate;
/*
* On each second we will play <osc_sample_rate> samples, so if we
* want to play the sine wave we'll need to increase the phase on
* each sample in such a way so that its period (1sec) fits within
* <osc_sample_rate> slots.
*/
osc->phase_step = ((double) (ONE_PERIOD)) / ((double) osc->sample_rate);
return 0;
}
/**
* osc_increase_phase - Increase the current sine phase
*
*/
void
osc_increase_phase(struct osc_state *osc)
{
/* Make sure we don't exceed one period
* note that sin/cos will not have an issue since they'll
* rewind themselves, however we risk an overflow of
* current_phase so be on the safe side. This will also
* take care of current_phase's sign since fmod will return
* a value with the same sign. */
osc->current_phase = fmod(osc->current_phase + osc->phase_step,
(double) (ONE_PERIOD));
return;
}
/*
* On the functions below we want to get some sine waves of a specific
* frequency that are all phase-synced (that means they all start at
* the same time or -in our case- from the same phase). To do that we'll
* need to playback a sine period <frequency> times faster, so we multiply
* the phase with the frequency.
*/
/**
* osc_get_sample_for_freq - Get a sample for the given frequency
* at the current phase.
*/
float
osc_get_sample_for_freq(const struct osc_state *osc, float freq)
{
double phase = osc->current_phase * (double) freq;
switch (osc->type) {
case OSC_TYPE_SINE:
return (float) sin(phase);
case OSC_TYPE_COSINE:
return (float) cos(phase);
default:
return 0;
}
}
/**
* osc_get_19Khz_sample - Get a 19KHz sample for the current
* phase.
*/
float
osc_get_19Khz_sample(const struct osc_state *osc)
{
return osc_get_sample_for_freq(osc, 19000.0);
}
/**
* osc_get_38Khz_sample - Get a 38KHz sample for the current
* phase.
*/
float
osc_get_38Khz_sample(const struct osc_state *osc)
{
return osc_get_sample_for_freq(osc, 38000.0);
}
/**
* osc_get_57Khz_sample - Get a 57KHz sample for the current
* phase.
*/
float
osc_get_57Khz_sample(const struct osc_state *osc)
{
return osc_get_sample_for_freq(osc, 57000.0);
}