PageRenderTime 33ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/libneil/src/plugins/btdsys_ringmod/ringmod.cpp

https://bitbucket.org/bucket_brigade/neil/
C++ | 420 lines | 263 code | 76 blank | 81 comment | 28 complexity | a76f1fd24160d76176de5da800f24181 MD5 | raw file
Possible License(s): GPL-2.0, BSD-3-Clause, LGPL-2.1
  1. // ported by jmmcd May 2008.
  2. /*
  3. Copyright (c) 2002, Edward Powley
  4. All rights reserved.
  5. Redistribution and use in source and binary forms, with or without
  6. modification, are permitted provided that the following conditions are met:
  7. * Redistributions of source code must retain the above copyright notice,
  8. this list of conditions and the following disclaimer.
  9. * Redistributions in binary form must reproduce the above copyright notice,
  10. this list of conditions and the following disclaimer in the documentation
  11. and/or other materials provided with the distribution.
  12. * Neither the name of BTDSys nor the names of its contributors may be used
  13. to endorse or promote products derived from this software without
  14. specific prior written permission.
  15. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  16. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  17. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  19. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  20. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  21. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  22. ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  24. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <cstdio>
  27. #include <zzub/signature.h>
  28. #include <zzub/plugin.h>
  29. #include <float.h>
  30. #include <stdlib.h>
  31. #include <string.h>
  32. #include <vector> //<-- we use a vector to store info about connections
  33. #define MAX_BUFFER_LENGTH 256
  34. typedef unsigned char byte;
  35. // Copied from lunar/dspbb.h
  36. void dsp_zero(float *b, int numsamples) {
  37. memset(b, 0, sizeof(float) * numsamples);
  38. }
  39. void dsp_copy(float *i, float *o, int numsamples) {
  40. memcpy(o, i, sizeof(float) * numsamples);
  41. }
  42. void dsp_add(float *i, float *o, int numsamples) {
  43. while (numsamples--) {
  44. *o++ += *i++;
  45. }
  46. }
  47. void dsp_copyamp(float *i, float *o, int numsamples, float s) {
  48. while (numsamples--) {
  49. *o++ = *i++ * s;
  50. }
  51. }
  52. void dsp_addamp(float *i, float *o, int numsamples, float s) {
  53. while (numsamples--) {
  54. *o++ += *i++ * s;
  55. }
  56. }
  57. class btdsys_ringmod;
  58. ////////////////////////////////////////////////////////////////////////
  59. // Parameters
  60. const zzub::parameter *paraDryOut = 0;
  61. const zzub::parameter *paraWetOut = 0;
  62. #pragma pack(1)
  63. class gvals
  64. {
  65. public:
  66. byte DryOut;
  67. byte WetOut;
  68. };
  69. #pragma pack()
  70. ////////////////////////////////////////////////////////////////////////
  71. //This little class is used to store info about each connected machine
  72. class CInput
  73. {
  74. public:
  75. char MacName[256];
  76. };
  77. class ringmod: public zzub::plugin
  78. {
  79. public:
  80. ringmod();
  81. virtual ~ringmod();
  82. virtual void process_events();
  83. virtual void init(zzub::archive *);
  84. virtual bool process_stereo(float **pin, float **pout, int numsamples, int mode);
  85. virtual bool process_offline(float **pin, float **pout, int *numsamples, int *channels, int *samplerate) { return false; }
  86. virtual void command(int i);
  87. virtual void load(zzub::archive *arc) {}
  88. virtual void save(zzub::archive *) {}
  89. virtual const char * describe_value(int param, int value);
  90. //virtual void OutputModeChanged(bool stereo) { }
  91. // ::zzub::plugin methods
  92. virtual void process_controller_events() {}
  93. virtual void destroy();
  94. virtual void stop() {}
  95. virtual void attributes_changed() {}
  96. virtual void set_track_count(int) {}
  97. virtual void mute_track(int) {}
  98. virtual bool is_track_muted(int) const { return false; }
  99. virtual void midi_note(int, int, int) {}
  100. virtual void event(unsigned int) {}
  101. virtual const zzub::envelope_info** get_envelope_infos() { return 0; }
  102. virtual bool play_wave(int, int, float) { return false; }
  103. virtual void stop_wave() {}
  104. virtual int get_wave_envelope_play_position(int) { return -1; }
  105. virtual const char* describe_param(int) { return 0; }
  106. virtual bool set_instrument(const char*) { return false; }
  107. virtual void get_sub_menu(int, zzub::outstream*) {}
  108. virtual void add_input(const char*, zzub::connection_type);
  109. virtual void delete_input(const char*, zzub::connection_type);
  110. virtual void rename_input(const char*, const char*);
  111. virtual void input(float**, int, float);
  112. virtual void midi_control_change(int, int, int) {}
  113. virtual bool handle_input(int, int, int) { return false; }
  114. //virtual void set_input_channels(char const *macname, bool stereo);
  115. virtual void process_midi_events(zzub::midi_message* pin, int nummessages) {}
  116. virtual void get_midi_output_names(zzub::outstream *pout) {}
  117. virtual void set_stream_source(const char* resource) {}
  118. virtual const char* get_stream_source() { return 0; }
  119. virtual void play_pattern(int index) {}
  120. virtual void configure(const char *key, const char *value) {}
  121. private:
  122. gvals gval;
  123. float drybuffer[2][MAX_BUFFER_LENGTH]; //buffers used for combining inputs
  124. float wetbuffer[2][MAX_BUFFER_LENGTH]; //set for max length of a stereo buffer
  125. float DryOut, WetOut; //amp levels
  126. bool SilentInput; //were any inputs silent?
  127. bool InitBuffer; //do we need to initialise the buffer?
  128. int CurrentInput; //which input are we working on?
  129. std::vector<CInput> Inputs; //info on the inputs
  130. inline int find_input (const char *macname); //find an input by name
  131. };
  132. ////////////////////////////////////////////////////////////////////////
  133. void ringmod::init (zzub::archive *a)
  134. {
  135. InitBuffer = true;
  136. // SetOutputMode(true);
  137. // pCB->SetnumOutputChannels(pCB->GetThisMachine(), 2);
  138. //Don't need any custom data
  139. }
  140. ////////////////////////////////////////////////////////////////////////
  141. void ringmod::process_events()
  142. {
  143. if (gval.DryOut != paraDryOut->value_none)
  144. DryOut = gval.DryOut / 128.0f;
  145. if (gval.WetOut != paraWetOut->value_none)
  146. WetOut = gval.WetOut / 128.0f;
  147. }
  148. ////////////////////////////////////////////////////////////////////////
  149. //This is called when a machine is connected to our machine's input.
  150. //For some reason it is called once with macname pointing to the name
  151. //of the machine, then again with macname == NULL. We'll just ignore
  152. //the NULL one.
  153. void ringmod::add_input(const char *macname, zzub::connection_type type)
  154. {
  155. if (macname != NULL)
  156. {
  157. CInput Temp;
  158. strcpy(Temp.MacName, macname);
  159. Inputs.push_back(Temp); //Add to end of connection vector
  160. }
  161. }
  162. ////////////////////////////////////////////////////////////////////////
  163. //This function is used to find the index of a named input. Just makes
  164. //life a bit easier.
  165. //Returns the index of the input, or -1 if not found.
  166. int ringmod::find_input(const char *macname)
  167. {
  168. for (unsigned int i=0; i<Inputs.size(); i++)
  169. {
  170. if (strcmp(Inputs[i].MacName, macname) == 0) return i;
  171. }
  172. printf("find_input returning -1\n");
  173. return -1;
  174. }
  175. ////////////////////////////////////////////////////////////////////////
  176. //This is called when a machine gets disconnected from our input.
  177. void ringmod::delete_input(const char *macname, zzub::connection_type type)
  178. {
  179. int i = find_input(macname);
  180. if (i != -1) Inputs.erase(Inputs.begin() + i);
  181. }
  182. ////////////////////////////////////////////////////////////////////////
  183. //This is called when a connected machine has its name changed.
  184. void ringmod::rename_input(const char *macoldname, const char *macnewname)
  185. {
  186. int i = find_input(macoldname);
  187. if (i != -1) strcpy(Inputs[i].MacName, macnewname);
  188. }
  189. ////////////////////////////////////////////////////////////////////////
  190. // //This is called when the stereo state of a connected machine changes.
  191. // void miex::SetInputChannels(const char *macname, bool stereo)
  192. // {
  193. // int i = pmi->FindInput(macname);
  194. // if (i != -1) pmi->Inputs[i].Stereo = stereo;
  195. // }
  196. ////////////////////////////////////////////////////////////////////////
  197. //The big one... this is where we process the input signals.
  198. //If numsamples == 0, then this particular machine is off.
  199. //amp is as set by the volume slider on the little triangle in machine view.
  200. void ringmod::input(float **psamples, int numsamples, float amp)
  201. {
  202. if (numsamples == 0) //machine is off
  203. {
  204. //If machine is off, we would multiply the whole buffer by zero.
  205. //ie we zero the whole buffer.
  206. dsp_zero(wetbuffer[0], MAX_BUFFER_LENGTH);
  207. dsp_zero(wetbuffer[1], MAX_BUFFER_LENGTH);
  208. SilentInput = true;
  209. }
  210. else
  211. {
  212. //Four separate loops -- but in zzub connections are always stereo, so we only need these two -- jmmcd.
  213. if (InitBuffer) //need to initialise it
  214. {
  215. for (int i=0; i < 2; i++)
  216. for (int j = 0; j < numsamples; j++)
  217. wetbuffer[i][j] = psamples[i][j] * amp;
  218. }
  219. else //mult with current wet buffer
  220. {
  221. for (int i=0; i < 2; i++)
  222. for (int j = 0; j < numsamples; j++)
  223. wetbuffer[i][j] *= psamples[i][j] * amp;
  224. }
  225. //Mix with dry buffer as normal
  226. dsp_addamp(psamples[0], drybuffer[0], numsamples, amp);
  227. dsp_addamp(psamples[1], drybuffer[1], numsamples, amp);
  228. }
  229. CurrentInput++; //increment our counter
  230. InitBuffer = false; //no need to init the buffer next time, we did it already
  231. }
  232. ////////////////////////////////////////////////////////////////////////
  233. //The Work() function is called after Input() has been called a bunch of
  234. //times. This is where we output what we collected, and get ready for the
  235. //next pass.
  236. bool ringmod::process_stereo(float **pin, float **pout, int numsamples, const int mode)
  237. {
  238. if (mode & zzub::process_mode_read)
  239. {
  240. if (mode & zzub::process_mode_write)
  241. {
  242. dsp_copyamp(drybuffer[0], pout[0], numsamples, DryOut);
  243. dsp_copyamp(drybuffer[1], pout[1], numsamples, DryOut);
  244. dsp_addamp(wetbuffer[0], pout[0], numsamples, WetOut);
  245. dsp_addamp(wetbuffer[1], pout[1], numsamples, WetOut);
  246. }
  247. }
  248. InitBuffer = true; //initialise it next time
  249. SilentInput = false; //assumption for next pass
  250. CurrentInput = 0; //set counter to first input
  251. dsp_zero(drybuffer[0], numsamples); //clear the buffer
  252. dsp_zero(drybuffer[1], numsamples); //clear the buffer
  253. return (mode & zzub::process_mode_read);
  254. }
  255. ////////////////////////////////////////////////////////////////////////
  256. void ringmod::command(const int i)
  257. {
  258. //The exciting about box
  259. char txt[10000];
  260. strcpy(txt,
  261. "BTDSys RingMod v1.0\n"
  262. "Š2002 Ed Powley (BTDSys)\n\n"
  263. "Comments/suggestions/bug reports to e@btd2001.freeserve.co.uk\n\n");
  264. sprintf(txt,"%s%zi inputs", txt, Inputs.size());
  265. for (unsigned int j=0; j<Inputs.size(); j++)
  266. sprintf(txt, "%s\n%i: %s", txt, j, Inputs[j].MacName);
  267. sprintf(txt, "%s\n", txt);
  268. _host->message(txt);
  269. }
  270. ////////////////////////////////////////////////////////////////////////
  271. char const *ringmod::describe_value(const int param, const int value)
  272. {
  273. static char txt[16];
  274. switch (param)
  275. {
  276. case 0: //dry out
  277. case 1: //wet out
  278. sprintf(txt, "%.2f%%", value / 1.28f);
  279. return txt;
  280. default:
  281. return NULL;
  282. }
  283. }
  284. ringmod::ringmod() {
  285. global_values = (void *) &gval;
  286. }
  287. ringmod::~ringmod() {
  288. }
  289. void ringmod::destroy() {
  290. delete this;
  291. }
  292. const char *zzub_get_signature() { return ZZUB_SIGNATURE; }
  293. struct btdsys_ringmod_plugin_info : zzub::info {
  294. btdsys_ringmod_plugin_info() {
  295. this->flags = zzub::plugin_flag_has_audio_input | zzub::plugin_flag_has_audio_output | zzub::plugin_flag_does_input_mixing;
  296. this->min_tracks = 0;
  297. this->max_tracks = 0;
  298. this->name = "BTDSys RingMod";
  299. this->short_name = "RingMod";
  300. this->author = "BTDSys";
  301. this->uri = "jamesmichaelmcdermott@gmail.com/effect/btdsys_ringmod;1";
  302. this->commands = "About";
  303. paraDryOut = &add_global_parameter()
  304. .set_byte()
  305. .set_name("Dry Out")
  306. .set_description("Dry Out (0=0% 0x80=100%)")
  307. .set_value_min(0)
  308. .set_value_max(0x80)
  309. .set_value_none(0xFF)
  310. .set_flags(zzub::parameter_flag_state)
  311. .set_value_default(0);
  312. paraWetOut = &add_global_parameter()
  313. .set_byte()
  314. .set_name("Wet Out")
  315. .set_description("Wet Out (0=0% 0x80=100%)")
  316. .set_value_min(0)
  317. .set_value_max(0x80)
  318. .set_value_none(0xFF)
  319. .set_flags(zzub::parameter_flag_state)
  320. .set_value_default(0x80);
  321. }
  322. virtual zzub::plugin* create_plugin() const { return new ringmod(); }
  323. virtual bool store_info(zzub::archive *data) const { return false; }
  324. } btdsys_ringmod_info;
  325. struct ringmodplugincollection : zzub::plugincollection {
  326. virtual void initialize(zzub::pluginfactory *factory) {
  327. factory->register_info(&btdsys_ringmod_info);
  328. }
  329. virtual const zzub::info *get_info(const char *uri, zzub::archive *data) { return 0; }
  330. virtual void destroy() { delete this; }
  331. // Returns the uri of the collection to be identified,
  332. // return zero for no uri. Collections without uri can not be
  333. // configured.
  334. virtual const char *get_uri() { return 0; }
  335. // Called by the host to set specific configuration options,
  336. // usually related to paths.
  337. virtual void configure(const char *key, const char *value) {}
  338. };
  339. zzub::plugincollection *zzub_get_plugincollection() {
  340. return new ringmodplugincollection();
  341. }