New Tool: Zynzilla, The Oscillator Editor


Version 0.21 is the newest release.

Sorry for causing all this trouble. Next time there will be a proper dev release on

Sept. 11th 2011:2.7 version uploaded.


  • fixed a bug when creating a new document, causing the tool to crash
  • fixed a bug where the phase shift value was not set for modulators, causing the tool to crash
  • fixed a bug where the modulators used the wrong harmonics, causing an unexpected waveform


  • up to 256 harmonic overtones
  • phase shifting of overtones
  • more waveforms (Chirp, Chebyshev, Diode, Gauss)
  • performance improvements (only needed overtones get rendered now, the more overtones you use, the longer rendering will take; if you use only one overtone, rendering will be almost as fast as with It-Aliens wave generator)

ZynZilla allows you to create waveforms with harmonic overtones. It is inspired by ZynAddSubFx and based on It-Alien’s wave generator. In the future I hope I will be able to add more of Zyn’s features to it. This is how it looks like now:

(ZynZilla, all those sliders are for setting the amplitudes and phases of the overtones)

This is how Zyn’s editor looks:


Planned Features:

  • Auto-updating of the sample

  • Waveform preview so users will be able to see the waveform they are editing
    For this feature I would need the ability to draw bitmaps from the renoise lua api. Something like bitmapview.setpixel( x,y,r,g,b ) or whatever. I had the idea to use a matrix of 1px bitmaps for that but something tells me that this isn’t gonna be very resource-friendly
    [edit]I guess API access to whatever widget you guys are using to draw the filter previews and custom LFO envelopes would be even nicer[/edit]

  • All of Zyn’s waveforms (for now, we have Chebyshev, Chirp, Diode, Gauss + all of It-Alien’s waveforms)

  • Adaptive Harmonics: change the position of the overtones based on the note and multi-note rendering

  • “Waveform Parameters” for each waveform to customize the shape of the base wave (partially done)

  • possibly Zyn-Style waveshaping

  • more modulation options besides FM (pulse- and ring-modulation)

…and more to come ;)

Do you think it would be feasible (performance-wise) to implement a waveform preview with a size of maybe 120x60px with 1px-bitmaps?

PS Contributions gladly accepted! If you want to team up, please don’t hesitate to drop me a message!

PPS I’m on github now!

Looks good!

look forward to the improvements and official publication!

Just seen on the RSS it`s official. Off to try.


Wait, what RSS?

Thanks for the info, Bantai.

Here’s an info for all users of ZynZilla: The lower your basenote is, the more accurate your sample will be. Here’s a sinewave rendered with C-0 as basenote:

Sinewave C-5:

“Sine” B-10:

So keep in mind: The higher your basenote, the more “digital overtones” your sample will have. This is because the samplerate of the generated samples is hardcoded at 44.1kHz (so a sample with a length of 1 second will consist of 44100 “stripes”). This will change in the future. But no matter how high you set your samplerate (or how low your basenote), there will always be digital artifacts or “pixels” in your waveform. If the samplerate of your driver is higher than 44.1kHz or you play low notes, choose a low base note in order to make more samples available for the Renoise audio engine to munch on.

oh yes! the custom waveform gen could use that too, not to mention nibbles :D :D

this is just awesome,thanks for sharing

You’re welcome :)

Sharing is fun! Finally I can give something back to the community. Hope it will be of use for you! Version 0.2 was just uploaded to the repo.

Can’t find it anymore in the tools browse section, update probably on review first for the moderators?

Thanks for the quick review!

I can’t find that variable on line 351, surely you meant line 230? However, real_phase_shift should always be set when the operate function is called by process_data(). Because right before that, in process_data() (l. 307), it iterates over all waveforms, and checks for the existence of the value in array_real_phase_shift:

if array_real_phase_shift[int_wave][int_multiplier] == nil then  
 array_real_phase_shift[int_wave][int_multiplier] = 0  

…so there is no way that a nil value could sneak into an arithmetric operation in operate() (as long as no one calls this function per hand)

[edit]I guess I was wrong! Sorry. I uploaded a fixed version (with comments!)[/edit]

initialize_wave() makes sure that array_real_phase_shift[int_wave] is set at this point.

But I agree that checking too often is better than checking not often enough (make the script crash). OTOH, better crash with an error message when something unexpected happens than silently replace the offending value and continue to compute garbage, making the user wonder why his waveform looks funky.

Btw. I’m sorry if there are some variable names that are a bit misleading. I’ll address that in the next release to make it more readable for you guys (and add some comments ;))

I will do it like that next time. Sorry to have caused confusion.

Great tool, have gotten some nice (clangy percussion) sounds out of this in combibation with the instrument editor, but also just encountered a crash after starting a new empty song, just after saving:
"Script ‘C:\Users\plugexpert\AppData\Roaming\Renoise\V2.6.0\Scripts\Tools\com.noisebeuter.ZynZilla.xrnx\main.lua’ failed in one of its notifiers. The notifier will be disabled to prevent further errors:

std::logic_error: ‘add notifier: the given function was already added to this notifier.’
stack traceback:
[C]: in function ‘add_notifier’
.\gui.lua:39: in function <.\gui.lua:33>"[/i]

yeah, I’ve come across that one too, it’s actually a bug in the custom waveform gen…

replace, in line 37:

if renoise.tool().app_new_document_observable:has_notifier(new_song_loaded)


if not renoise.tool().app_new_document_observable:has_notifier(new_song_loaded)

Thanks for reporting. I fixed it in the git repo. There’s not going to be a new release until tomorrow night, so if you need it working right now just replace line 37 in gui.lua like Johann mentioned (or grab the file from github if you don’t feel like hacking the source).

PS It’s nice to see that someone is using my tool!

Oh noes, you were right! :panic:

I just uploaded a new version with this and other bugs fixed.

has this one been updated for 2.7.x yet?

second this, really curious to try this out in 2.7. thanks!!


It looks like its open source for anyone who knows how to re-version it to 2.7

Manually changed manifest.xml to read API version 2.0

Now it loads but I can not test it.

-- This function is called when the user presses the "Generate" button. It is  
-- responsible for creating the sample and calling process_data() for each  
-- sample.   
function generate()  
 local instrument =  
 local int_sample_index =  
 local int_samples = table.getn(instrument.samples)  
 local buffer_new,sample_new  
 if(int_samples == 0) then   
 sample_new = instrument:insert_sample_at(int_sample_index)   
 sample_new =  
 buffer_new = sample_new.sample_buffer  
 if int_frames == 0 then   
 int_frames = SAMPLE_FREQUENCY / note_to_frequency(int_note)   

I can not find a Generate button anywhere and I still don’t get LUA well enough but don’t think there is a keyboard shortcut assigned to it. Had a quick look at gui.lua and it seems there is mention of a Generate and a Reset button right at the end but I can not find either…

 -- main layout  
 local button_generate = vb:button {  
 text = "Generate",  
 tooltip = "Hit this button to generate a custom wave with the specified features.",  
 width = "100%",  
 notifier = function()  
 local button_reset = vb:button {  
 text = "Reset",  
 width = "100%",  
 tooltip = "Reset all data",  
 notifier = function()  
 "Parameters Reset",  
 "Are you sure you want to reset all parameters data?",{"Yes","No"}  
 ) == "Yes"   

Guess this is a serious work in progress. Anybody feel they can go somewhere with it. (BatBoy: isn’t anything .xrnx pretty much open source? It’s all based upon the Renoise API, which is public, and viewable from within Renoise once you enable the Script Editor.)

It doesn’t work because at least two lines need to be changed to the new functionality:

sample_new.base_note = int_note-1
instrument.split_map[int_note] = int_sample_index

the splitmap no longer exists and the base note is tied to the keyzone now.

Yeah thought the instrument changes would mean it wouldn’t work without modification. That doesn’t explain why I don’t see the Generate and Reset buttons to even try and test it though does it?