Moselle, a new software synth, nearing release

DSP, Plugin and Host development discussion.

Whats your reaction to this sample program?

I can't even look at it much less understand it.
5
21%
I could figure it out with time and the manual.. but won't.
13
54%
I get it but it'd be easier to read if it were programmed in <name of synth software>. (Tell me what software and share a screenshot if you have time.)
0
No votes
Its as clear to me as it'd be with any other system I've used, even with zero Moselle experience.
1
4%
Its Patching Nirvana! Do not sleep, Frank, until you have delivered a working binary to me!
5
21%
 
Total votes: 24

RELATED
PRODUCTS

Post

Swiss Frank wrote:... and know 2 octaves means twice the frequency
Count again 8-)
"Until you spread your wings, you'll have no idea how far you can walk." Image

Post

Whyterabbyt I'm astounded and very thankful. That looks like hours of work.

It sounds like you know a fair amount about Max/MSP too--I assumed it was more on the level of the diagram you generated.

As for copying response curves exactly and what not--I'm not that fussed. Moselle has the exponent and since that preserves min and max values of controllers, envelopes, LFOs etc. outputting 0..1, I tend to throw those around a lot for scaling. They're not mission-critical and if I was trying to copy some other system's patch (eg one with 5 set response curves or what-not) I'd probably not match their scaling that precisely either.
whyterabbyt wrote:those parts were formulae not routing/structure or 'significant' signal processing blocks, and the issue was more about reconstructing those formulae
This is actually an interesting point: Moselle's main attraction (to the extent it has one) may be that the insignificant modules kind of disappear.

BTW nice sig.

Post

whyterabbyt wrote:
Frantz wrote:
Swiss Frank wrote:I wanted a bit more experience with Win32 programming, since I've been Linux/Unix all my life.
32 bit only?
Win32 is the name of the most-commonly used [url=http://en.wikipedia.org/wiki/Windows_API]API[/quote
for windows. There is a Win64, which is effectively the 64-bit implementation, but I think its safe to say that, in general, anything which conforms to the current non-deprecated subset of the Win32 API is compilable for x64 without issues.
Actually I'd say most of the deprecated stuff works just as well, as long as you differentiate between LONG and LONGPTR (which you can do for 32-bit too, but it's necessary for 64-bit because of the different sizes of the types; this is also necessary for some functions like GetWindowLong/GetWindowLongPtr, which again are just two names of the same thing for 32-bit). There's a few more corner cases, but for the most part you can use a Win32 API reference from 1995 and it'll all just work fine in 64 [including the stuff that was already deprecated in 1995 really]. ;)
Last edited by mystran on Mon Jun 17, 2013 2:24 pm, edited 1 time in total.

Post

Swiss Frank wrote:Whyterabbyt I'm astounded and very thankful. That looks like hours of work.
To be honest, the basic structure was about 5-10 minutes. Reproducing the formulae properly probably brought it nearer to an hour, some of that because I was trying to find the closest analogous module for the equation. It wasnt a full hour, though, I had time to eat lunch too. ;)
It sounds like you know a fair amount about Max/MSP too--I assumed it was more on the level of the diagram you generated.
No, not as high level as that out of the box. For the functionality of module that the G2, or Reaktor can provide out the box, ie relatively close to that of an analogue modular, you'd more or less have to roll your own, it doesnt really ship with anything prebuilt. The documentation provides plenty of examples that would get you part-way, but, for example, your oscillator with sync and PWM would more or less have to be all your own work. These days, I'd suspect anyone wanting to do so would probably get furthest doing so with MAX's new GEN system. I think its one reason its always traditionally appealed to the 'academic' set, whereas something comparitive like Reaktor or Synthedit with a decent set of higher level building blocks gets more truck from 'regular' musicians.
BTW nice sig.
cheers... :tu:

By the way, in case you think Im sounding very dismissive of text-based stuff, I do feel that there is certainly a place for it, from CSound through to writing new modules in 'proper' programming languages, and that some points in the hierarchy of 'tiered' modular systems like Reaktor (cf Reaktor Core) might be easier to work with if they werent graphical. But I guess I tend to feel that the bits that work best that way are the most linear signal-flow/calculation areas, not the mid-high level architectural layout...
my other modular synth is a bugbrand

Post

whyterabbyt wrote: By the way, in case you think Im sounding very dismissive of text-based stuff, I do feel that there is certainly a place for it, from CSound through to writing new modules in 'proper' programming languages, and that some points in the hierarchy of 'tiered' modular systems like Reaktor (cf Reaktor Core) might be easier to work with if they werent graphical. But I guess I tend to feel that the bits that work best that way are the most linear signal-flow/calculation areas, not the mid-high level architectural layout...
I think the approach taken by SynthMaker is actually pretty sensible: you can build blocks out of lower-level blocks, but then at low-level you can have blocks which are just containers for arbitrary code. In case of SynthMaker that means raw DSP code, but you could use the same approach with a higher-level textual language too.

Post

mystran wrote:
whyterabbyt wrote: By the way, in case you think Im sounding very dismissive of text-based stuff, I do feel that there is certainly a place for it, from CSound through to writing new modules in 'proper' programming languages, and that some points in the hierarchy of 'tiered' modular systems like Reaktor (cf Reaktor Core) might be easier to work with if they werent graphical. But I guess I tend to feel that the bits that work best that way are the most linear signal-flow/calculation areas, not the mid-high level architectural layout...
I think the approach taken by SynthMaker is actually pretty sensible: you can build blocks out of lower-level blocks, but then at low-level you can have blocks which are just containers for arbitrary code. In case of SynthMaker that means raw DSP code, but you could use the same approach with a higher-level textual language too.
Indeed, Synthmaker lets you write in a sort of higher-level code, but also gives you access to an assembler-level as well. And now Flowstone adds a third programmable tier with Ruby. (Unfortunately the 'framework' of SM (re 64bit, events, et al), and the change in focus of the devs, has been a bit of an achilles heel for audio development)
my other modular synth is a bugbrand

Post

Moselle Development Diary...

Today I've been working on stupid boring stuff that nonetheless no-one else can use this without:

1) actually being able to SELECT your MIDI source (instead of being hardcorded to the 4th device on the list)

2) errors actually appear in a window on the app, instead of in the debug output logfile.



The Delay seems to work with some in-depth test cases but I should try to break it before I assume its finished. One feature I've been thinking about: it currently rounds delay times to the nearest sample, but I've thought about putting in interpolation and actually letting you specify a delay of 1/440 sec if you want a middle-A comb filter, etc... something tells me it'll sound like crap if I don't oversample.

The Stored Waveform Oscillator sounds worse than the Naive Math Oscillator, which I need to look into. (I suspect I need to oversample when I fill in buffers; right now, I generate waveforms into a buffer the precise number of samples to hold its lowest note. By default waveforms are generated every 3 semis or so, because Moselle's too much of a CPU hog to run any faster than 44.1kHz, bringing the Nyquist down to within a few notes of human hearing.)

Post

Swiss Frank wrote: My intended audience is musicians who are interested in creating their own patches (most don't nowadays--in fact most never did); know what a decibel is and know 2 octaves means twice the frequency; and has ANY experience at all with like a spreadsheet or word processor.
I certainly fit the profile but if I felt the need for a modular synth, my first choice might be uhe's Zebra or Bazille. Something that gives immediate feedback and wouldn't require me to completely remove my musician hat and put on my propeller hat.

I understand the appeal of working with text. In fact, I spend a significant part of my day looking at code in Textpad for my job. But when it's time for music, typing formulas in a text editor doesn't sound immediately appealing.

In any case, it's not about me. As they say, build it and they will come.

Post

I think the approach taken by SynthMaker is actually pretty sensible: you can build blocks out of lower-level blocks, but then at low-level you can have blocks which are just containers for arbitrary code. In case of SynthMaker that means raw DSP code, but you could use the same approach with a higher-level textual language too.
This sounds like something I've been worried about for years but haven't sat down and figured out: how to take a "basic" patch as a building block for another? It shouldn't be too hard: right now a patch is just a calculation with Note, Velocity, and MIDI controllers as inputs and a sound output called "Mono" as its output. No reason it couldn't take an audio (or control) input as an input instead of or in addition to Note, and have its output be available to the mother patch instead of going directly to speaker jack.
Unfortunately the 'framework' of SM (re 64bit, events, et al), and the change in focus of the devs, has been a bit of an achilles heel for audio development
I'd love to hear more about this if you have time. I don't know the current field or its problems hardly at all, which is kind of idiotic given the amount of time I've sunk into making a solution for a problem I don't understand. :cry:

Post

Development Diary.

The Stored-Waveform Oscillator needed oversampling, based on initial testing. With oversampling (and linear interpolation) it sounds VERY good to my ears. Turns out at 44.1kHz synthesis, 2x oversampling is enough. Less sounds bad, but more doesn't bring additional benefit in most cases(to my ears). And the advantage over the alternatives (eg no oversampling; 16x oversampling but no linear interpolations; or the naive-math oscillator making straight-line sawtooths) is at least 60dB S/N I'd guess.

In order to do this project I needed to add more usability features to the Oscilloscope: now reads out the number samples, frequency, and MIDI note/detune. Added a grid behind the graphs. Now takes keypresses to switch between various display modes.

Also I'm now giving the user their choice of MIDI devices on a menu, instead of hard-coding to open up MIDI input #4 :)

-----------

Coming up next: a Skew() module, which will be needed for portamento among other things. Portamento may not be musically useful with a LIFO note cache, so I'll be working on a Monophonic mode (with and without retriggering).

Post

You can specify the waveform for Moselle's Stored Waveform Oscillator (SWO) with keywords "Sawtooth" or "Square", or manually specify harmonics with "Harm1 = 1" "Harm2 = 1/2" etc.

But there's a third way, that turned out to be unexpectedly powerful, and I thought it might be of wider interest.

You can specify a single formula called "HarmGeneric" that is evaluated over and over, for every harmonic, for every sample that is made.

As each sample is started, two variables are set that you can use in your formula should you choose: FreqFrom and FreqTo, giving the frequency range over which this current waveform sample will be used. These allow you to alter your waveform across the keyboard (over and above the built-in band limiting), to the point of having keyboard splits or even different sounds for each key.

Then as the SWO goes through each harmonic, others are set: Harmonic (the harmonic number) and FreqHarm (its frequency). These let you base the harmonic
strength on the harmonic number (eg, to make sawtooth vs. square) or its
frequency (to do band-pass and band-cut filtering at the waveform-generation stage).

Using the various math and Excel-like logic functions of Moselle, you can therefore specify every harmonic of every note in a very compact fashion.

Here's a list I'm including in my tutorial, though stripped of the explanations that would be insultingly basic to this list's readers.

Note this isn't the spec, these are from working patches.

----------------------

# SAWTOOTH

#HarmGeneric = 1

# MELLOW SAWTOOTH (fades like triangle)

#HarmGeneric = 1 / Harmonic

# SEMI-MELLOW SAWTOOTH (fades slower than triangle)

#HarmGeneric = 1 / Harmonic ^ .6

# AGGRESSIVE SAWTOOTH (harmonics get somewhat louder as they go)

#HarmGeneric = 1 * Harmonic ^ .2

# BANDPASS SAWTOOTH

#HarmGeneric = IF( AND( FreqHarm >= 220, FreqHarm <= 3520), 1, 0 )

# BANDCUT SAWTOOTH

#HarmGeneric = IF( AND( FreqHarm >= 220, FreqHarm <= 3520), 0, 1 )

# DUAL BANDPASS SAWTOOTH

#HarmGeneric = IF( OR( AND( FreqHarm >= 650, FreqHarm <= 1050), AND( FreqHarm >= 1360, FreqHarm <= 1860) ), 1, 0 )

# SINE

#HarmGeneric = IF( Harmonic = 1, 1, 0 )

# SQUARE

# \ is a modulo operator: "If Harmonic divided by 2 gives remainder 1, then
# make the harmonic full-volume; otherwise no harmonic at all."

#HarmGeneric = IF( Harmonic \ 2 = 1, 1, 0 )

# EVERY THIRD (1 4 7...)

#HarmGeneric = IF( Harmonic \ 3 = 1, 1, 0 )

# EVERY FOURTH (1 5 9 ...)

#HarmGeneric = IF( Harmonic \ 4 = 1, 1, 0 )

# UP-DOWN PULSE

#HarmGeneric = 1/40 * Harmonic

# TRIANGLE

#HarmGeneric = IF( Harmonic \ 2 = 1, 1/Harmonic , 0 ) * IF( Harmonic \ 4 = 1, 1, -1 )

# TRIANGLE "LITE"

# Same sound, wrong phase but who cares, less typing

#HarmGeneric = IF( Harmonic \ 2 = 1, 1/Harmonic , 0 )

# ALL OCTAVES

#HarmGeneric = IF( InList( Harmonic, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 ), 1, 0 )

# HAMMOND OCTAVES

#HarmGeneric = IF( InList( Harmonic, 1, 2, 4, 8, 16 ), 1, 0 )

# HAMMOND FULL RANKS

#HarmGeneric = IF( InList( Harmonic, 1, 3, 2, 4, 6, 8, 10, 12, 16 ), 1, 0 )

# PRIME HARMONICS

#HarmGeneric = IF( InList( Harmonic, 2, 3, 5, 7, 11, 13, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199 ), 1, 0 )

# INFINITE-SLOPE LOW-PASS SAWTOOTH

#HarmGeneric = IF( Harmonic < 15, 1, 0 )

# INFINITE-SLOPE HIGH-PASS SAWTOOTH

#HarmGeneric = IF( Harmonic > 1, 1, 0 )

# POOR MAN'S SPLIT

# Sawtooth below middle C, Square above.

#HarmGeneric = IF( OR( Harmonic \ 2 = 1, FreqTo < 261), 1, 0 )

# TOTALLY RANDOM

# Lets give every note on the keyboard its own totally random spectrum.

#HarmGeneric = RANDOM()

-------------------------------------

The complete functioning patch containing one of these; the lack of envelopes
etc. actually is true to what you'd expect from a Hammond Octave waveform...

Code: Select all

[SWO1]
Waveform      = Generic
HarmGeneric   = IF( InList( Harmonic, 1, 2, 4, 8, 16 ), 1, 0 )

[Voice]
Mono        = SWO1:Audio

Post

Development Diary:

Got a "Slew" module working, with fixed-time or fixed-rate skew, working for linear and exponential curves.

Made a second module called "Portamento" out of it, same code but different default inputs: eg defaults to exponential curve, continuing output where it left off on a previous voice, and taking as input the master frequency of the voice. Its output the has pitchbend, transpose and detune applied. Assuming you don't want to re-invent the basic mapping of note to pitch with pitchbend, to add portamento to a given patch such as:

Code: Select all

[Osc1]
Frequency = Voice:Frequency

[Voice]
Mono = Osc1:Audio
becomes the following. (The "Bypass" is option and just an example.)

Code: Select all

[Osc1]
Frequency = Portamento:Frequency

[Voice]
Mono = Osc1:Audio

[Portamento]
Time = .25
Bypass = NOT( PortamentoPedal )
[/code]

Post

MP3s with sample audio please. :)

Post

Frantz wrote:MP3s with sample audio please. :)
Thank you for the enthusiasm!

I'm getting so close to actually releasing it that I'm torn between uploading a few youtubes or just continuing development...

When I make such a sample I will mention it here.

Post

Development Diary:

The new Skew module seems to be complete. Took a few days to think of all the weirdest cases, but I think its "finished." After thinking about it in the back of my mind for years I couldn't think of a clean way to do portamento, but 3/4 of the way through doing it in a hacky way, I came up with a clean way. Problem is that, uniquely so far, Portamento means something about a voice depends not on this voice or user input or patch-wide modules etc., but something from LAST voice. Its surprising that every module seems to need about one unique language feature that nothing else does.

----

A half dozen small bug fixes (but its been weeks since a bug resulted in crash; the bugs are getting smaller and smaller).

----

Writing lots of tutorial/regression test patches. I think you'll be able to learn 90% of Moselle just by reading the tutorials.

----

Writing ref docs in Word, but half my mind is thinking how most people will only ever read the PDF, and if you're reading on your computer, HTML with hotlinks, and without page numbers etc., is probably better. But word's HTML output is crap, and if you WANT printed, then printed HTML is also crap.

----

Got some "power editing" features in mind for the editor. Keyword completion (a la Visual Studio) is one, but so is having a "cookbook." For instance, open up an empty patch. Right click and get a menu. The menu has an entry "cookbook" with a sub-menu. The sub-menu shows each module type.

You choose Stored Waveform Oscillator (SWO). THAT has a sub-sub-menu with 40-50 different defaults including saw, square, triangle, every-third-harmonic, every-fourth-harmonic, PW, PWM (with attendant per-patch LFO), LPF'd saw, HPF'd saw, bandpassed saw, bandcut saw, octaves, prime number harmonics, lofi saws and squares, maybe a couple-dozen "Wave Osc"-type wave forms a la DW-8000/TS-10 etc., yadayadayada.

Then you go to Cookbook->Envelope and choose from Piano-like, pad-like, organ-like, clav, etc. etc.

I don't know if V1.0 needs to wait until I have such a feature working. V1.0 is really just supposed to be a proof-of-concept that people can stand the textual language. OTOH the editing "assistance" may be an important part of getting acceptance.

----

I want to write a "Map" object that works for anything from alternative tunings to waveshaping...

But the main "musical" coding left is mono/poly/unison. That's going to require a fair re-write, moving the kbd assignment code from the MIDI engine to the Patch class...

Post Reply

Return to “DSP and Plugin Development”