File: vibrating_string.h

package info (click to toggle)
lmms 1.2.2%2Bdfsg1-2
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 55,144 kB
  • sloc: cpp: 159,861; ansic: 98,570; python: 2,555; sh: 551; makefile: 27; xml: 18
file content (271 lines) | stat: -rw-r--r-- 6,879 bytes parent folder | download | duplicates (2)
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
/*
 * vibrating_string.h - model of a vibrating string lifted from pluckedSynth
 *
 * Copyright (c) 2006-2007 Danny McRae <khjklujn/at/yahoo/com>
 * 
 * This file is part of LMMS - https://lmms.io
 *
 * 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 2 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 (see COPYING); if not, write to the
 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301 USA.
 *
 */
#ifndef _VIBRATING_STRING_H
#define _VIBRATING_STRING_H

#include <stdio.h>
#include <stdlib.h>

#include "lmms_basics.h"

class vibratingString
{

public:
	vibratingString(	float _pitch, 
				float _pick, 
				float _pickup,
				float * impluse,
				int _len,
				sample_rate_t _sample_rate,
				int _oversample,
				float _randomize,
				float _string_loss,
				float _detune,
				bool _state );
	
	inline ~vibratingString()
	{
		delete[] m_outsamp;
		delete[] m_impulse;
		vibratingString::freeDelayLine( m_fromBridge );
		vibratingString::freeDelayLine( m_toBridge );
	}

	inline sample_t nextSample()
	{	
		sample_t ym0;
		sample_t ypM;
		for( int i = 0; i < m_oversample; i++)
		{
			// Output at pickup position
			m_outsamp[i] = fromBridgeAccess( m_fromBridge, 
								m_pickupLoc );
			m_outsamp[i] += toBridgeAccess( m_toBridge, 
								m_pickupLoc );
		
			// Sample traveling into "bridge"
			ym0 = toBridgeAccess( m_toBridge, 1 );
			// Sample to "nut"
			ypM = fromBridgeAccess( m_fromBridge,
						m_fromBridge->length - 2 );

			// String state update

			// Decrement pointer and then update
			fromBridgeUpdate( m_fromBridge, 
						-bridgeReflection( ym0 ) );
			// Update and then increment pointer
			toBridgeUpdate( m_toBridge, -ypM );
		}
		return( m_outsamp[m_choice] );
	}

private:
	struct delayLine
	{
		sample_t * data;
		int length;
		sample_t * pointer;
		sample_t * end;
	} ;

	delayLine * m_fromBridge;
	delayLine * m_toBridge;
	int m_pickupLoc;
	int m_oversample;
	float m_randomize;
	float m_stringLoss;
	
	float * m_impulse;
	int m_choice;
	float m_state;
	
	sample_t * m_outsamp;

	delayLine * initDelayLine( int _len, int _pick );
	static void freeDelayLine( delayLine * _dl );
	void resample( float *_src, f_cnt_t _src_frames, f_cnt_t _dst_frames );
	
	/* setDelayLine initializes the string with an impulse at the pick
	 * position unless the impulse is longer than the string, in which
	 * case the impulse gets truncated. */
	inline void setDelayLine( delayLine * _dl, 
					int _pick,
					const float * _values, 
					int _len,
					float _scale,
					bool _state )
	{
		float r;
		float offset;
		
		if( not _state )
		{
			for( int i = 0; i < _pick; i++ )
			{
				r = static_cast<float>( rand() ) /
						RAND_MAX;
				offset =  ( m_randomize / 2.0f -
						m_randomize ) * r;
				_dl->data[i] = _scale *
						_values[_dl->length - i - 1] +
						offset;
			}
			for( int i = _pick; i < _dl->length; i++ )
			{
				r = static_cast<float>( rand() ) /
						RAND_MAX;
				offset =  ( m_randomize / 2.0f -
						m_randomize ) * r;
				_dl->data[i] = _scale * 
						_values[i - _pick]  + offset ;
			}
		}
		else
		{
			if( _len + _pick > _dl->length )
			{
				for( int i = _pick; i < _dl->length; i++ )
				{
					r = static_cast<float>( rand() ) /
							RAND_MAX;
					offset =  ( m_randomize / 2.0f -
							m_randomize ) * r;
					_dl->data[i] = _scale *
							_values[i-_pick] +
							offset;
				}
			}
			else
			{
				for( int i = 0; i < _len; i++ )
				{
					r = static_cast<float>( rand() ) /
							RAND_MAX;
					offset =  ( m_randomize / 2.0f -
							m_randomize ) * r;
					_dl->data[i+_pick] = _scale *
								_values[i] +
								offset;
				}
			}
		}
	}

	/* toBridgeUpdate(dl, insamp);
	* Places "nut-reflected" sample from upper delay-line into
	* current lower delay-line pointer position (which represents
	* x = 0 position).  The pointer is then incremented (i.e. the
	* wave travels one sample to the left), turning the previous
	* position into an "effective" x = L position for the next
	* iteration. */
	inline void toBridgeUpdate( delayLine * _dl, sample_t _insamp )
	{
		register sample_t * ptr = _dl->pointer;
		*ptr = _insamp * m_stringLoss;
		++ptr;
		if( ptr > _dl->end )
		{
			ptr = _dl->data;
		}
		_dl->pointer = ptr;
	}

	/* fromBridgeUpdate(dl, insamp);
	* Decrements current upper delay-line pointer position (i.e.
	* the wave travels one sample to the right), moving it to the
	* "effective" x = 0 position for the next iteration.  The
	* "bridge-reflected" sample from lower delay-line is then placed
	* into this position. */
	inline void fromBridgeUpdate( delayLine * _dl, 
							sample_t _insamp )
	{
		register sample_t * ptr = _dl->pointer;
		--ptr;
		if( ptr < _dl->data )
		{
			ptr = _dl->end;
		}
		*ptr = _insamp * m_stringLoss;
		_dl->pointer = ptr;
	}

	/* dlAccess(dl, position);
	* Returns sample "position" samples into delay-line's past.
	* Position "0" points to the most recently inserted sample. */
	static inline sample_t dlAccess( delayLine * _dl, int _position )
	{
		sample_t * outpos = _dl->pointer + _position;
		while( outpos < _dl->data )
		{
			outpos += _dl->length;
		}
		while( outpos > _dl->end )
		{
			outpos -= _dl->length;
		}
		return( *outpos );
	}

	/*
	*  Right-going delay line:
	*  -->---->---->--- 
	*  x=0
	*  (pointer)
	*  Left-going delay line:
	*  --<----<----<--- 
	*  x=0
	*  (pointer)
	*/

	/* fromBridgeAccess(dl, position);
	* Returns spatial sample at position "position", where position zero
	* is equal to the current upper delay-line pointer position (x = 0).
	* In a right-going delay-line, position increases to the right, and
	* delay increases to the right => left = past and right = future. */
	static inline sample_t fromBridgeAccess( delayLine * _dl, 
								int _position )
	{
		return( dlAccess( _dl, _position ) );
	}

	/* toBridgeAccess(dl, position);
	* Returns spatial sample at position "position", where position zero
	* is equal to the current lower delay-line pointer position (x = 0).
	* In a left-going delay-line, position increases to the right, and
	* delay DEcreases to the right => left = future and right = past. */
	static inline sample_t toBridgeAccess( delayLine * _dl, int _position )
	{
		return( dlAccess( _dl, _position ) );
	}

	inline sample_t bridgeReflection( sample_t _insamp )
	{
		return( m_state = ( m_state + _insamp ) * 0.5 );
	}

} ;

#endif