|
Post by keurslagerkurt on Nov 26, 2021 17:56:40 GMT
I'll kick this board off here! Had a project for a rainy day today: a voltage controlled sine LFO for AE, something that would be a great addition I think. It evolved from a sketch which I wrote for my work, where we needed a three-phase sine wave output to control a motor. It were my first real steps into Arduino, so it was equally fun, exciting AND frustrating. I got a working code for my own Arduino Nano, but my Grains module seems to be bricked. So if anyone could test this code for Grains specifically and report back, that would be great. Sketch gives control with pots & voltage over lfo rate & amplitude. Third pot gives an offset control. Third CV in is used for as Sync trigger input to start the lfo from the middle spot. More info in the README over at github. And also lots of comments on how the sketch runs in the code itself. github.com/ZVanMoerkerke/GrainsAE_VC_LFO_SinePlease remember that I'm 100% a beginner in Arduino, so all constructive commentary is very, very welcome. I'm not yet capable to get in the nitty gritty of handling timers in the real registers, so I resort to the more high level functions from Arduino itself (god this made me appreciate them more after scrolling through 100 pages of Atmel datasheet!). Specifically, if anybody could give tips to make the loop() run faster, that would be great. Max speed is now only about 10Hz, I noticed that activating the analog inputs was the biggest time consumption. It would be supercool if the LFO could go up to 50Hz or something. At last a very small sound clip where the SVFilter is controlled by the LFO. An enveloppe is send to Grains CV 1 & 2, creating a rising frequency ánd rising amplitude of the LFO at the same time. soundcloud.com/zzzvm/vclfo-test/s-4AhtZklq0H6?si=41114f460d2343ee8bd2933764940f95Cheers Zeno / Kurt
|
|
|
Post by keurslagerkurt on Nov 26, 2021 23:52:53 GMT
duddex was so Nice to test it, really feels great to see it work in another rack! 😃 For anyone testing, you can see this as the 'alpha' version. So all testing commentary is def useful. I noticed that the knobs' sensitivity might need some further tweaking for example. Please Tell me whatever you think could be improved.
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 689
|
Post by namke on Nov 27, 2021 13:58:12 GMT
With regard to making it run faster, I usually split the control reading stuff from the sample-generation stuff. Since reading the analogue inputs is relatively time consuming, I leave that in the main loop() function but then put the sound generating stuff into a tuner-ticked interrupt routine (this also has the benefit that the sample generation is regularised; more important for audio generation, but not to be disregarded!
|
|
|
Post by keurslagerkurt on Nov 27, 2021 15:28:14 GMT
With regard to making it run faster, I usually split the control reading stuff from the sample-generation stuff. Since reading the analogue inputs is relatively time consuming, I leave that in the main loop() function but then put the sound generating stuff into a tuner-ticked interrupt routine (this also has the benefit that the sample generation is regularised; more important for audio generation, but not to be disregarded! Ah, that could def be the winning tip! Got any example grains code to point me towards the 'tuner-ticked interrupt routine'? Been messing with ISR's, but with very moderate success so far 😅
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 689
|
Post by namke on Nov 27, 2021 18:49:43 GMT
|
|
|
Post by keurslagerkurt on Nov 27, 2021 19:39:30 GMT
I'll check out the bits & bytes tomorrow, thanks for sharing 😃
Also, didn't know there was a grains library at all haha!
|
|
|
Post by pt3r on Nov 28, 2021 11:51:41 GMT
Are there any good clear sources that explain all those register setups I see in the code? I clearly have the feeling that I don't understand even half of what's going on in the setup and #define blocks. My arduino code is more arduino like not all this cryptic C register stuff.
|
|
|
Post by duddex on Nov 28, 2021 11:59:06 GMT
I found this YouTube video helpful: And many YouTube tutorials about Arduino programming recommend reading the ATmega328P datasheet
|
|
|
Post by duddex on Nov 28, 2021 14:54:00 GMT
[...] Also, didn't know there was a grains library at all haha! Some of the firmware modules on github.com/aemodular/GRAINS (e.g. the ByteBeats Crossfader and Euclidean-Palindrome) use this class in the code: class GrainsIO // This is our main class to encapsulate any GRAINS related stuff, mainly I/O { public: // vars altered by interrupt static bool div32; static bool div16; static volatile bool new_sample; static volatile byte audio_data; static volatile byte pot_cv; static volatile byte ibb; static volatile byte pot_selector; static volatile byte cv[4];
// Main processing "callback" - this is were all user-code for this framework should go if possible. static void GrainsIO::process();
static byte a_out; // Analogue output has to go here static int d_out; // Digital output has to go here }; The actual implementation of the modules should be in void GrainsIO::process()I am not yet completely sure how to use this class. I still try to understand these modules...
|
|
|
Post by keurslagerkurt on Nov 28, 2021 16:38:25 GMT
I found this YouTube video helpful: And many YouTube tutorials about Arduino programming recommend reading the ATmega328P datasheetI usually find Great Scotts tutorials to be a bit too quick to follow, but this one is quite ideal in this case. Thanks for sharing!
|
|
|
Post by keurslagerkurt on Nov 28, 2021 17:37:28 GMT
Having a hard time understanding the #define's at the start, as well as how the ISR is 'tuned' and running. I can imagine that if I know at which frequency it interrupts, I can attach a counter to see when it 'overflows' a number that is set by the wanted frequency. Not sure if this is the way to do it? That would be essentially how I did it now (with micros()), but of course with the ISR's this would be quicker and more precise, which is what I'm after.
However, seems to be too complicated for a n00b like me yet. I did give the original script a quick update, which makes it possible to go SUPER SLOW and also makes it easy to set your own desired frequency range for the LFO at the start.
|
|
|
Post by pt3r on Nov 28, 2021 20:11:08 GMT
That was indeed a very informative video. thanks for sharing.
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 689
|
Post by namke on Nov 28, 2021 21:02:41 GMT
Having a hard time understanding the #define's at the start, as well as how the ISR is 'tuned' and running. I can imagine that if I know at which frequency it interrupts, I can attach a counter to see when it 'overflows' a number that is set by the wanted frequency. Not sure if this is the way to do it? That would be essentially how I did it now (with micros()), but of course with the ISR's this would be quicker and more precise, which is what I'm after. However, seems to be too complicated for a n00b like me yet. I did give the original script a quick update, which makes it possible to go SUPER SLOW and also makes it easy to set your own desired frequency range for the LFO at the start. (This might not help, but here goes ) For my 'grains sine', two timers are used: - Timer1 is used to generate the PWM output, so we'll ignore that one for the moment
- Timer0 is the one responsible for the 'sample-rate' interrupt, in this case the sample rate is set at 25kHz (this is the SRATE value defined in calc.h).
The timer has a pair of registers which are useful: a prescaler and a 'match' value. Every clock tick increments a counter in the timer, and when the counter reaches the 'match' value, two things happen: firstly an interrupt is fired (if configured) and secondly the timer count is reset to zero. Since the timer is ticked at a rate derived from the system clock (which runs at 16MHz for the Arduino), a prescaler is configured to make the interrupts happen at a more manageable rate. This block of code calculates the two values (prescaler and match): // let the preprocessor calculate the various register values 'coz // they don't change after compile time #if ((F_TIM/(SRATE)) < 255) #define T1_MATCH ((F_TIM/(SRATE))-1) #define T1_PRESCALE _BV(CS00) //prescaler clk/1 (i.e. 8MHz) #else #define T1_MATCH (((F_TIM/8L)/(SRATE))-1) #define T1_PRESCALE _BV(CS01) //prescaler clk/8 (i.e. 1MHz) #endif
These are done in #defines because that way the calculation is done by the compiler rather than the run-time code. Apologies for the naming - they should really be prefixed with 'T0'!! The following code actually configures the timer with these values: /////////////////////////////////////////////// // Set up Timer/Counter0 for sample-rate ISR TCCR0B = 0; // stop the timer (no clock source) TCNT0 = 0; // zero the timer
TCCR0A = _BV(WGM01); // CTC Mode TCCR0B = T1_PRESCALE; // Set the prescaler and therefore start the timer OCR0A = T1_MATCH; // calculated match value TIMSK0 |= _BV(OCIE0A); // enable the interrupt when counter matches OCR0A
Now that we have an interrupt being fired, we must have an interrupt handler which will be called. For this we define a function like this: ISR(TIMER0_COMPA_vect) { ... }
This function needs to bw written to calculate the next sample value and write it to the PWM output register (the responsibility of timer1). The description of what goes on in the ISR (e.g. how do we know what value to output next?) is probably better written as a separate post
|
|
namke
wonkystuff
electronics and sound, what's not to like?!
Posts: 689
|
Post by namke on Nov 28, 2021 21:37:28 GMT
|
|
|
Post by duddex on Dec 23, 2021 16:19:11 GMT
[...] I got a working code for my own Arduino Nano, but my Grains module seems to be bricked. So if anyone could test this code for Grains specifically and report back, that would be great. [...] What is the behavior of your Grains now? I think I also bricked my module (other post in this subforum). I am unable to upload new code because the serial port does not show up in the Arduino IDE. Do you have a similar problem? Have you an idea how to unbrick the module?
|
|
|
Post by keurslagerkurt on Dec 23, 2021 16:35:40 GMT
[...] I got a working code for my own Arduino Nano, but my Grains module seems to be bricked. So if anyone could test this code for Grains specifically and report back, that would be great. [...] What is the behavior of your Grains now? I think I also bricked my module (other post in this subforum). I am unable to upload new code because the serial port does not show up in the Arduino IDE. Do you have a similar problem? Have you an idea how to unbrick the module? I still have to mail Robert. Mine did never work well, it always had this ton of noise, but i could upload patches so i think the nano inside is actually fine. I know that pt3r had a story about bricking and unbricking his nano that is a bit similar to yours maybe
|
|
|
Post by pt3r on Dec 23, 2021 17:19:55 GMT
There is indeed also a thread here where I explained how I bricked my pro micro board due to a buffer overflow error and managed to unbrick it, but it's basically the same procedure explained in the above link.
|
|