1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2004 Masanao Izumo <iz@onicos.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 
20     effect.c - To apply sound effects.
21     Mainly written by Masanao Izumo <iz@onicos.co.jp>
22 
23     Interfaces:
24     void init_effect(void);
25     do_effect(int32_t* buf, int32_t count);
26 */
27 
28 #include <string.h>
29 #include <stdlib.h>
30 
31 #include "effect.h"
32 #include "instrum.h"
33 #include "playmidi.h"
34 #include "reverb.h"
35 
36 
37 namespace TimidityPlus
38 {
39 
40 
41 
42 #define SIDE_CONTI_SEC	10
43 #define CHANGE_SEC		2.0
44 
init_effect()45 void Effect::init_effect()
46 {
47 	effect_left_right_delay(NULL, 0);
48 	reverb->init_for_effect();
49 }
50 
51 /*
52 	* Left & Right Delay Effect
53 	*/
effect_left_right_delay(int32_t * buff,int32_t count)54 void Effect::effect_left_right_delay(int32_t *buff, int32_t count)
55 {
56 	int32_t save[AUDIO_BUFFER_SIZE * 2];
57 	int32_t pi, i, j, k, v, backoff;
58 	int b;
59 	int32_t *p;
60 
61 	if (buff == NULL)
62 	{
63 		memset(prev, 0, sizeof(prev));
64 		return;
65 	}
66 	if (effect_lr_mode == 0 || effect_lr_mode == 1 || effect_lr_mode == 2)
67 		b = effect_lr_mode;
68 	else
69 		return;
70 	count *= 2;
71 	backoff = 2 * (int)(playback_rate * effect_lr_delay_msec / 1000.0);
72 	if (backoff == 0)
73 		return;
74 	if (backoff > count)
75 		backoff = count;
76 	if (count < AUDIO_BUFFER_SIZE * 2)
77 	{
78 		memset(buff + count, 0, 4 * (AUDIO_BUFFER_SIZE * 2 - count));
79 		count = AUDIO_BUFFER_SIZE * 2;
80 	}
81 	memcpy(save, buff, 4 * count);
82 	pi = count - backoff;
83 	if (b == 2)
84 	{
85 		if (turn_counter == 0)
86 		{
87 			turn_counter = SIDE_CONTI_SEC * playback_rate;
88 			/* status: 0 -> 2 -> 3 -> 1 -> 4 -> 5 -> 0 -> ...
89 				* status left   right
90 				* 0      -      +		(right)
91 				* 1      +      -		(left)
92 				* 2     -> +    +		(right -> center)
93 				* 3      +     -> -	(center -> left)
94 				* 4     -> -    -		(left -> center)
95 				* 5      -     -> +	(center -> right)
96 				*/
97 			status = 0;
98 			tc = 0;
99 		}
100 		p = prev;
101 		for (i = 0; i < count; i += 2, pi += 2)
102 		{
103 			if (i < backoff)
104 				p = prev;
105 			else if (p == prev)
106 			{
107 				pi = 0;
108 				p = save;
109 			}
110 			if (status < 2)
111 				buff[i + status] = p[pi + status];
112 			else if (status < 4)
113 			{
114 				j = (status & 1);
115 				v = (int32_t)(rate0 * buff[i + j] + rate1 * p[pi + j]);
116 				buff[i + j] = v;
117 				rate0 += dr, rate1 -= dr;
118 			}
119 			else
120 			{
121 				j = (status & 1);
122 				k = !j;
123 				v = (int32_t)(rate0 * buff[i + j] + rate1 * p[pi + j]);
124 				buff[i + j] = v;
125 				buff[i + k] = p[pi + k];
126 				rate0 += dr, rate1 -= dr;
127 			}
128 			tc++;
129 			if (tc == turn_counter)
130 			{
131 				tc = 0;
132 				switch (status)
133 				{
134 				case 0:
135 					status = 2;
136 					turn_counter = (CHANGE_SEC / 2.0) * playback_rate;
137 					rate0 = 0.0;
138 					rate1 = 1.0;
139 					dr = 1.0 / turn_counter;
140 					break;
141 				case 2:
142 					status = 3;
143 					rate0 = 1.0;
144 					rate1 = 0.0;
145 					dr = -1.0 / turn_counter;
146 					break;
147 				case 3:
148 					status = 1;
149 					turn_counter = SIDE_CONTI_SEC * playback_rate;
150 					break;
151 				case 1:
152 					status = 4;
153 					turn_counter = (CHANGE_SEC / 2.0) * playback_rate;
154 					rate0 = 1.0;
155 					rate1 = 0.0;
156 					dr = -1.0 / turn_counter;
157 					break;
158 				case 4:
159 					status = 5;
160 					turn_counter = (CHANGE_SEC / 2.0) * playback_rate;
161 					rate0 = 0.0;
162 					rate1 = 1.0;
163 					dr = 1.0 / turn_counter;
164 					break;
165 				case 5:
166 					status = 0;
167 					turn_counter = SIDE_CONTI_SEC * playback_rate;
168 					break;
169 				}
170 			}
171 		}
172 	}
173 	else
174 	{
175 		for (i = 0; i < backoff; i += 2, pi += 2)
176 			buff[b + i] = prev[b + pi];
177 		for (pi = 0; i < count; i += 2, pi += 2)
178 			buff[b + i] = save[b + pi];
179 	}
180 	memcpy(prev + count - backoff, save + count - backoff, 4 * backoff);
181 }
182 
do_effect(int32_t * buf,int32_t count)183 void Effect::do_effect(int32_t *buf, int32_t count)
184 {
185 	int32_t nsamples = count * 2;
186 	int reverb_level = (timidity_reverb < 0)
187 		? -timidity_reverb & 0x7f : DEFAULT_REVERB_SEND_LEVEL;
188 
189 	/* for static reverb / chorus level */
190 	if (timidity_reverb == 2 || timidity_reverb == 4
191 		|| (timidity_reverb < 0 && !(timidity_reverb & 0x80))
192 		|| timidity_chorus < 0)
193 	{
194 		reverb->set_dry_signal(buf, nsamples);
195 		/* chorus sounds horrible
196 			* if applied globally on top of channel chorus
197 			*/
198 		if (timidity_reverb == 2 || timidity_reverb == 4
199 			|| (timidity_reverb < 0 && !(timidity_reverb & 0x80)))
200 			reverb->set_ch_reverb(buf, nsamples, reverb_level);
201 		reverb->mix_dry_signal(buf, nsamples);
202 		/* chorus sounds horrible
203 			* if applied globally on top of channel chorus
204 			*/
205 		if (timidity_reverb == 2 || timidity_reverb == 4
206 			|| (timidity_reverb < 0 && !(timidity_reverb & 0x80)))
207 			reverb->do_ch_reverb(buf, nsamples);
208 	}
209 	/* L/R Delay */
210 	effect_left_right_delay(buf, count);
211 }
212 
my_mod(int32_t x,int32_t n)213 int32_t Effect::my_mod(int32_t x, int32_t n)
214 {
215 	if (x >= n)
216 		x -= n;
217 	return x;
218 }
219 
220 }