PageRenderTime 27ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/cmt/src/lofi.cpp

#
C++ | 418 lines | 318 code | 72 blank | 28 comment | 14 complexity | d941048b2f834bd7180afdfcff6422da MD5 | raw file
Possible License(s): GPL-2.0
  1. /* lofi.cpp
  2. Lo Fi - Simulate low quality audio equipment
  3. Copyright (c) 2001 David A. Bartold
  4. Computer Music Toolkit - a library of LADSPA plugins. Copyright (C)
  5. 2000 Richard W.E. Furse. The author may be contacted at
  6. richard@muse.demon.co.uk.
  7. This library is free software; you can redistribute it and/or
  8. modify it under the terms of the GNU General Public Licence as
  9. published by the Free Software Foundation; either version 2 of the
  10. Licence, or (at your option) any later version.
  11. This library is distributed in the hope that it will be useful, but
  12. WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. General Public License for more details.
  15. You should have received a copy of the GNU General Public License
  16. along with this library; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  18. 02111-1307, USA. */
  19. /*****************************************************************************/
  20. #include <malloc.h>
  21. #include <math.h>
  22. #include <stdlib.h>
  23. #include "cmt.h"
  24. #define PORT_IN_LEFT 0
  25. #define PORT_IN_RIGHT 1
  26. #define PORT_OUT_LEFT 2
  27. #define PORT_OUT_RIGHT 3
  28. #define PORT_CRACKLING 4
  29. #define PORT_OVERLOADING 5
  30. #define PORT_BANDWIDTH 6
  31. #define NUM_PORTS 7
  32. #ifndef PI
  33. #define PI 3.14159265358979
  34. #endif
  35. #ifndef MIN
  36. #define MIN(x,y) ((x)<(y)?(x):(y))
  37. #endif
  38. #ifndef MAX
  39. #define MAX(x,y) ((x)>(y)?(x):(y))
  40. #endif
  41. class Pop
  42. {
  43. public:
  44. float x;
  45. float dx;
  46. float amp;
  47. float pwr;
  48. Pop *next;
  49. Pop (float dx, float amp, float pwr, Pop *next);
  50. ~Pop ();
  51. };
  52. Pop::Pop (float _dx,
  53. float _amp,
  54. float _pwr,
  55. Pop *_next)
  56. : x (0.0), dx (_dx), amp (_amp), pwr (_pwr), next (_next)
  57. {
  58. }
  59. Pop::~Pop ()
  60. {
  61. delete next;
  62. }
  63. class Record
  64. {
  65. public:
  66. int rate;
  67. int amount; /* 0 -> 100% */
  68. Pop *pops;
  69. LADSPA_Data process (LADSPA_Data sample);
  70. void setAmount (int _amount);
  71. Record (int sample_rate);
  72. ~Record ();
  73. };
  74. Record::Record (int sample_rate)
  75. : rate (sample_rate),
  76. amount (0),
  77. pops (NULL)
  78. {
  79. }
  80. Record::~Record ()
  81. {
  82. delete pops;
  83. }
  84. static Pop *
  85. record_pop_new (Record *record,
  86. Pop *next)
  87. {
  88. return new Pop ((rand () % 1500 + 500.0) / record->rate,
  89. (rand () % 50) / 10000.0,
  90. 1.0,
  91. next);
  92. }
  93. static Pop *
  94. record_pop_loud_new (Record *record,
  95. Pop *next)
  96. {
  97. return new Pop ((rand () % 500 + 2500.0) / record->rate,
  98. (rand () % 100) / 400.0 + 0.5,
  99. (rand () % 50) / 20.0,
  100. next);
  101. }
  102. LADSPA_Data
  103. Record::process (LADSPA_Data sample)
  104. {
  105. Pop *pop;
  106. Pop **pop_prev;
  107. /* Add some crackle */
  108. if (rand () % rate < rate * amount / 4000)
  109. pops = record_pop_new (this, pops);
  110. /* Add some loud pops */
  111. if (rand () % (rate * 10) < rate * amount / 400000)
  112. pops = record_pop_loud_new (this, pops);
  113. /* Compute pops */
  114. pop_prev = &pops;
  115. pop = *pop_prev;
  116. while (pop != NULL)
  117. {
  118. if (pop->x >= 0.5)
  119. sample += (pow ((1.0 - pop->x) * 2.0, pop->pwr) - 0.5) * pop->amp;
  120. else
  121. sample += (pow (pop->x * 2.0, pop->pwr) - 0.5) * pop->amp;
  122. pop->x += pop->dx;
  123. if (pop->x > 1.0)
  124. {
  125. *pop_prev = pop->next;
  126. pop->next = NULL;
  127. delete pop;
  128. }
  129. else
  130. pop_prev = &pop->next;
  131. pop = *pop_prev;
  132. }
  133. return sample;
  134. }
  135. void
  136. Record::setAmount (int _amount)
  137. {
  138. amount = _amount;
  139. }
  140. class Compressor
  141. {
  142. public:
  143. int rate;
  144. double amp;
  145. double up;
  146. double down;
  147. float vol;
  148. float clamp_hi;
  149. float clamp_lo;
  150. LADSPA_Data process (LADSPA_Data sample);
  151. void setClamp (float clamp);
  152. Compressor (int sample_rate, float clamp);
  153. };
  154. Compressor::Compressor (int sample_rate, float clamp)
  155. : rate (sample_rate), amp (0.5),
  156. up (1.0 / pow (0.5, 20.0 / sample_rate)),
  157. down (pow (0.5, 50.0 / sample_rate)),
  158. vol (0.5), clamp_hi (clamp), clamp_lo (1.0 / clamp)
  159. {
  160. }
  161. LADSPA_Data
  162. Compressor::process (LADSPA_Data sample)
  163. {
  164. sample *= amp;
  165. if (fabs (sample) > vol)
  166. {
  167. amp *= down;
  168. if (amp < clamp_lo)
  169. amp = clamp_lo;
  170. }
  171. else
  172. {
  173. amp *= up;
  174. if (amp > clamp_hi)
  175. amp = clamp_hi;
  176. }
  177. return sample;
  178. }
  179. void
  180. Compressor::setClamp (float clamp)
  181. {
  182. clamp_hi = clamp;
  183. clamp_lo = 1.0 / clamp;
  184. }
  185. static inline LADSPA_Data
  186. distort (LADSPA_Data in)
  187. {
  188. if (in > 0.0F)
  189. return (in * 1.0F) / (in + 1.0F) * 2.0F;
  190. else
  191. return -(-in * 1.0F) / (-in + 1.0F) * 2.0F;
  192. }
  193. class BandwidthLimit
  194. {
  195. public:
  196. int rate;
  197. float x;
  198. float dx;
  199. void setFreq (float freq);
  200. LADSPA_Data process (LADSPA_Data sample);
  201. BandwidthLimit (int _rate, float _freq);
  202. };
  203. BandwidthLimit::BandwidthLimit (int _rate, float _freq)
  204. : rate (_rate), x (0.0), dx (_freq / _rate)
  205. {
  206. }
  207. LADSPA_Data
  208. BandwidthLimit::process (LADSPA_Data sample)
  209. {
  210. if (sample >= x)
  211. sample = MIN (x + dx, sample);
  212. else
  213. sample = MAX (x - dx, sample);
  214. x = sample;
  215. return sample;
  216. }
  217. void
  218. BandwidthLimit::setFreq (float freq)
  219. {
  220. dx = freq / rate;
  221. }
  222. class LoFi : public CMT_PluginInstance {
  223. Record *record;
  224. Compressor *compressor;
  225. BandwidthLimit *bandwidth_l;
  226. BandwidthLimit *bandwidth_r;
  227. int last_trigger;
  228. public:
  229. LoFi(const LADSPA_Descriptor *,
  230. unsigned long s_rate)
  231. : CMT_PluginInstance (NUM_PORTS),
  232. record (new Record (s_rate * 2)),
  233. compressor (new Compressor (s_rate * 2, 1.6)),
  234. bandwidth_l (new BandwidthLimit (s_rate, 8000.0)),
  235. bandwidth_r (new BandwidthLimit (s_rate, 8000.0)) {
  236. }
  237. ~LoFi() {
  238. delete bandwidth_l;
  239. delete bandwidth_r;
  240. delete compressor;
  241. delete record;
  242. }
  243. static void
  244. activate (LADSPA_Handle Instance) {
  245. LoFi *lofi = (LoFi*) Instance;
  246. lofi->bandwidth_l->setFreq (8000);
  247. lofi->bandwidth_r->setFreq (8000);
  248. lofi->compressor->setClamp (1.6);
  249. lofi->record->setAmount (0);
  250. }
  251. static void
  252. run(LADSPA_Handle Instance,
  253. unsigned long SampleCount) {
  254. LoFi *lofi = (LoFi*) Instance;
  255. unsigned long i;
  256. LADSPA_Data **ports = lofi->m_ppfPorts;
  257. LADSPA_Data clamp;
  258. lofi->bandwidth_l->setFreq (ports[PORT_BANDWIDTH][0]);
  259. lofi->bandwidth_r->setFreq (ports[PORT_BANDWIDTH][0]);
  260. if (ports[PORT_OVERLOADING][0] > 99.0)
  261. clamp = 100.0;
  262. else
  263. clamp = 100.0 / (100.0 - ports[PORT_OVERLOADING][0]);
  264. lofi->compressor->setClamp (clamp);
  265. lofi->record->setAmount ((int) ports[PORT_CRACKLING][0]);
  266. for (i = 0; i < SampleCount; i++)
  267. {
  268. LADSPA_Data sample_l, sample_r;
  269. sample_l = ports[PORT_IN_LEFT][i];
  270. sample_r = ports[PORT_IN_RIGHT][i];
  271. sample_l = lofi->compressor->process (sample_l);
  272. sample_r = lofi->compressor->process (sample_r);
  273. sample_l = lofi->bandwidth_l->process (sample_l);
  274. sample_r = lofi->bandwidth_r->process (sample_r);
  275. sample_l = distort (sample_l);
  276. sample_r = distort (sample_r);
  277. sample_l = lofi->record->process (sample_l);
  278. sample_r = lofi->record->process (sample_r);
  279. ports[PORT_OUT_LEFT][i] = sample_l;
  280. ports[PORT_OUT_RIGHT][i] = sample_r;
  281. }
  282. }
  283. };
  284. static LADSPA_PortDescriptor g_psPortDescriptors[] =
  285. {
  286. LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT,
  287. LADSPA_PORT_AUDIO | LADSPA_PORT_INPUT,
  288. LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT,
  289. LADSPA_PORT_AUDIO | LADSPA_PORT_OUTPUT,
  290. LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
  291. LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT,
  292. LADSPA_PORT_CONTROL | LADSPA_PORT_INPUT
  293. };
  294. static const char * const g_psPortNames[] =
  295. {
  296. "In (Left)",
  297. "In (Right)",
  298. "Out (Left)",
  299. "Out (Right)",
  300. "Crackling (%)",
  301. "Powersupply Overloading (%)",
  302. "Opamp Bandwidth Limiting (Hz)"
  303. };
  304. static LADSPA_PortRangeHint g_psPortRangeHints[] =
  305. {
  306. /* Hints, Lower bound, Upper bound */
  307. { 0, 0.0, 0.0 },
  308. { 0, 0.0, 0.0 },
  309. { 0, 0.0, 0.0 },
  310. { 0, 0.0, 0.0 },
  311. { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW |
  312. LADSPA_HINT_INTEGER, -0.1, 100.1 },
  313. { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 0.0, 100.0 },
  314. { LADSPA_HINT_BOUNDED_ABOVE | LADSPA_HINT_BOUNDED_BELOW, 1.0, 10000.0 }
  315. };
  316. void
  317. initialise_lofi() {
  318. CMT_Descriptor * psDescriptor;
  319. psDescriptor = new CMT_Descriptor
  320. (1227,
  321. "lofi",
  322. 0 /* Sorry, this module is not RT capable, run() calls malloc() */,
  323. "Lo Fi",
  324. CMT_MAKER("David A. Bartold"),
  325. CMT_COPYRIGHT("2001", "David A. Bartold"),
  326. NULL,
  327. CMT_Instantiate<LoFi>,
  328. LoFi::activate,
  329. LoFi::run,
  330. NULL,
  331. NULL,
  332. NULL);
  333. for (int i = 0; i < NUM_PORTS; i++)
  334. psDescriptor->addPort(
  335. g_psPortDescriptors[i],
  336. g_psPortNames[i],
  337. g_psPortRangeHints[i].HintDescriptor,
  338. g_psPortRangeHints[i].LowerBound,
  339. g_psPortRangeHints[i].UpperBound);
  340. registerNewPluginDescriptor(psDescriptor);
  341. }