Return Styles: Pseud0ch, Terminal, Valhalla, NES, Geocities, Blue Moon. Entire thread

FM Synthesis Libraries

Name: Anonymous 2009-12-09 23:28

I'm thinking about using a realtime FM synth for music and sound effects in my next game. I'd write a library myself, but I don't want to waste my time if there's already something good out there. The thing is, google turned up no results. Am I going to have to get cracking on my own?

Name: Anonymous 2009-12-13 20:52

>>35
I wrote one back in 2003. It's as easy as you think.

Some junk like:
audio[i] = sin((freq * i * 2 * M_PI / SAMPLE_RATE) * normalize(mod_signal[i]))

or whatever. I didn't check that so you should, or wait for someone else to go full retard on me for leaving out the semicolon and they'll probably catch the meaningful mistakes while they're at it. Convert it to LUTs and add AA/interpolation if you like (probably best for FM.) normalize() makes an element of audio[] suitable for use as a modulation signal, and exactly how it works is dependent on your data type.

For primary operators, initialize an empty modulation signal buffer to whatever is neutral and use the same effect. This way you can feedback into the same operator by writing to the init'd mod buffer.

Speaking of data types, use floats with DC0 = 0. Least of all benefits of this is that simply zeroing the mod buffer will be correct initialization.

Oh, I almost forgot:

#define SEMITONE_RATIO (1.0594630943592)
freq = pow(SEMITONE_RATIO, midi_note_number)


I think that's right for the midi spec but I can't remember. For some reason I have it split up like this in some code I have laying around:

  r = note%12;
  q = note/12;
  f = pow(SEMITONE_RATIO, r);
  f *= pow(2, q -4);


... probably using those extra values for some other thing but I can't be arsed to check.

There you go. Route those into each other according to whatever crazy idea you have and do ADSR (sample data multiplier maps) on the 'key' events.

If you are tempted to use LADSPA plugins for any reason, and happen to be operating in stereo but are stuck with a mono effect:

M = (L+R)/2;
S = (L-R)/2;
L = M + S;
R = M - S;


L and R being left and right channels, M (mid) being the mono signal and S (side) being the stereo phase signal. Run the mono process on M and take the output as M', combine M' with S to get the (processed) L' and R' values. Not for use with effects that demean the stereo image.

Name: Anonymous 2009-12-13 21:36

>>41
#define SEMITONE_RATIO (1.0594630943592)
FUCK YOU

Name: Anonymous 2009-12-13 21:49

>>42
What's the problem? Too precise for you? Don't like #define even for the purposes of illustration? I'd like to know. (Not really.)

Name: Anonymous 2009-12-13 22:23

>>39
Dude, you're a furry? That's fucked up.

Name: Anonymous 2009-12-13 23:27

>>43
I'm raging on musical grounds.

Name: Anonymous 2009-12-13 23:38

>>45
Oh well the value is accurate* and the name is appropriate if not ideal.

*: I know some prefer a fixed table with fudged values on the grounds that certain ratios come out better, but a) I hate that and b) the FM engines I've investigated don't do it.

Name: Anonymous 2009-12-14 0:06

>>46
The value is worthless. Play a real interval, why don't you? The best thing about writing your own synth is that you don't have to put up with whatever shitty scale the majority assumes as universal.

Name: Anonymous 2009-12-14 0:36

>>47
You're shitting on me because you don't like the dominant western temperament? It's piss easy to implement and more importantly probably what OP is looking for. Take it up with someone else.

Name: Anonymous 2009-12-14 2:19

Going with 2612 emulation is a pretty good choice since you can dump instruments from any Genesis game using Gens KMod.  Also MAME emulates the 2612 and all their code is freely available.

Of course, the 2612 is a pretty limited chip in a number of ways and it would probably be easier to compose for something more powerful.  But you could still use 2612 code as a starting point that you could then turn into something cooler if you wanted to.

Name: Anonymous 2009-12-14 2:33

>>49
What about SNES?  I liked the SNES 1000 times more than the Sega Genesis.

Name: Anonymous 2009-12-14 2:52

>>48
You're shitting on music.

It's piss easy to implement
Just like everything else?

probably what OP is looking for.
Wow, you're a dickhead. OP didn't even do anything to you.

Name: Anonymous 2009-12-14 3:40

>>50
SNES instruments aren't FM, they're just samples.

Name: Anonymous 2009-12-14 3:48

>>37
IIRC OPL and OPL2 (AdLib, the original Sound Blaster) had only two operators per voice. OPL3 (SB16) could pair channels for four-operator voices, later versions added more operators and algorithms.

The Sega Saturn has a moderately interesting scheme which I haven't seen in other chips (though I assume the Dreamcast's one works the same). Each of the 32 channels can serve as an FM operator, but as there is no waveform ROM they all play either noise generated by the chip or a waveform from RAM which can be an "oscillator" signal or a normal sample. Each channel can itself have two FM modulation sources that are freely selectable, so you're not limited to a built-in set of FM algorithms. Each channel, including those working as FM operators, can be sent to either the output mixer (with individual pan and volume settings) or to one of the built-in DSP's 16 inputs for effects processing.

SID still beats all.

Name: Anonymous 2009-12-14 4:32

>>53
did you mean oscillators?

Name: Anonymous 2009-12-14 5:46

>>54
Yamaha calls them operators
. Possibly because they output a waveform stored in an internal ROM, rather than using a "real" oscillator.

Name: Anonymous 2009-12-14 10:49

>>50,52
Yes, SNES is so much better than Genesis, and that's because it isn't shitty FM instruments. Nintendo hopped the wavetable train before most other people, and it paid off tremendously for them.

(Disagree? I defy you to make the claim that any FM-based MIDI output is even a fraction as realistic-sounding or even decent as a wavetable player. It's an absurd claim, the only thing FM can do passably is a bell. Everything else will sound like varying degrees of ass.)

>>53
SID is cheeseball three-channel junk that's only capable of making blippy noises, and you're a stupid hipster for pretending it's any good.

Name: Anonymous 2009-12-14 10:58

>>56
Congratulations, you have a shitty taste in old musics.

Name: Anonymous 2009-12-14 12:16

hax my opl3

Name: A.J. Cates 2009-12-14 12:30

Nintendo still leads with the best sound in there games. They now use live Orchestras for there music, and if you want an uber bad ass game I suggest you do the same.

Name: Anonymous 2009-12-14 12:31

>>56,57
I like both.

Name: Anonymous 2009-12-14 12:55

>>59
Sorry but classical music is for homos and casuals

Name: Anonymous 2009-12-14 13:13

>>61
Shut the fuck up and listen to some JSB Sebastian Bach.

Name: Anonymous 2009-12-14 13:26

>>61
(ಠ_ಠ)

Name: Anonymous 2009-12-14 13:55

>>51
Well that's two rounds of full retard and still no issues with the FM code, so OP if you're reading, that code is probably rock-solid.

>>56
Blah. Dude, words are coming from where you poop. SEE A DOCTOR.

Name: Anonymous 2009-12-14 13:58

>>61
Classical music is very beautiful, you uncultured philistine.

Name: Anonymous 2009-12-14 14:08

module Main where

import Data.Bits
import Data.Char
import Data.List
import System.IO

makeU8 x freq = (((sin (x * (2 * pi) * (freq / 8000))) + 1) * 64.0)

tone freq length amplitude x =
  if x >= length
    then []
    else (floor ((makeU8 x freq) * amplitude)) : tone freq length (0.9995 * amplitude) (x + 1)

tones = [("##", 8000),
         ("b1", 61.735),
         ("c2", 65.406),
         ("d2", 73.416),
         ("e2", 82.407),
         ("f2", 87.307),
         ("g2", 97.999),
         ("a2", 110.00),
         ("b2", 123.47),
         ("c3", 130.81),
         ("d3", 146.83),
         ("e3", 164.81),
         ("f3", 174.61),
         ("g3", 196.00),
         ("a3", 220.00),
         ("b3", 246.94),
         ("c4", 261.63),
         ("d4", 293.66),
         ("e4", 329.63),
         ("f4", 349.23),
         ("g4", 392.00)]

t x = case lookup x tones of
        Just y -> (tone y 2000 0.75 0) :: [Int]
        Nothing -> []

main :: IO ()
main = do
  let notesl =["d2",
               "d3",
               "b2",
               "f2",
               "b2",
               "b1",
               "c2",
               "d2",
               "e2"]
  let notes = ["##", "g3", "a3",
               "b3", "d4", "c4",
               "c4", "e4", "d4", -- from d4
               "d4", "g4", "f4",
               "g4", "d4", "c4",
               "g3", "a3", "b3",
               "c4", "d4", "e4",
               "d4", "c4", "b3",
               "a3", "b3", "g3"] -- end
{--               "f3", "g3", "a3",
               "d3", "f3", "a3",
               "c4", "b3", "a3",
               "b3", "g3", "a3",
               "b3", "d4", "c4",
               "c4", "e4", "d4",
               "d4", "g4", "f4",
               "g4", "d4", "b3",
               "g3", "a3", "b3"]--}
--               "e3", "d4", "c4"
--               ]
  let blank = t "##"
  let inter = (intersperse "##" notes)
  let interl = (intersperse "##" notesl)
  let strs = concat (map t notes)
  let strsl = concat (map (\ x -> (concat (replicate 5 (t x))) ++ blank) notesl)
  let bytes = map chr (zipWith (+) strs strsl)
  hPutStr stdout bytes

Name: Anonymous 2009-12-14 14:41

>>57
ONE WORD, THE FORCED BACKTRACKING OF SUPER METROID
THREAD OVER

Name: Anonymous 2009-12-14 14:49

>>56
Maybe if you're retarded enough to think the purpose of a synth is to not sound like a synth. Hello: if you want it to sound like the real thing, play the real thing.

Name: Anonymous 2009-12-14 14:52

>>67
Just after the python post and everything. There should be some kind of prize for you.

Name: Anonymous 2009-12-14 14:58

>>68
A synthesizer is supposed to synthesize the sounds of real instruments.  The more accurate the sound is the better the synthesizer is.  Enjoy you're inferior sounds while you can, criminal scum.

Name: Anonymous 2009-12-14 15:08

Name: Anonymous 2009-12-14 15:17

>>69
U MENA HASKAL

Name: Anonymous 2009-12-14 15:22

>>72
I did that just for you.

Name: Anonymous 2009-12-14 16:50

Name: Anonymous 2009-12-14 17:07

Name: Anonymous 2009-12-14 17:14

module Main where

import Data.Char
import Data.List
import System.IO

sineWave freq = map (\ x -> ((sin (x * (2 * pi) * (freq / 8000))) + 1) / 4) [0..]

tone freq length amplitude =
    zipWith (\ a b -> (floor (a * b * 255))) (sineWave freq)
  $ adsr 250 500 0.5 300
  $ replicate length amplitude

adsr a d s r xs =
  let (as, as') = splitAt a xs
      (ds, ds') = splitAt d as'
      (ss, rs)  = splitAt ((length ds') - r) ds'
  in concat [zipWith (*) as [(fromIntegral x) / (fromIntegral a) | x <- [0..a]],
             zipWith (*) ds [s + ((fromIntegral x) / (fromIntegral d)) * s | x <- (reverse [0..d])],
             map (*s) ss,
             zipWith (*) rs [((fromIntegral x) / (fromIntegral r)) * s | x <- (reverse [0..r])]]

pianoNotes = ["A0","A#0","B0","C1","C#1","D1","D#1","E1","F1","F#1","G1","G#1",
              "A1","A#1","B1","C2","C#2","D2","D#2","E2","F2","F#2","G2","G#2",
              "A2","A#2","B2","C3","C#3","D3","D#3","E3","F3","F#3","G3","G#3",
              "A3","A#3","B3","C4","C#4","D4","D#4","E4","F4","F#4","G4","G#4",
              "A4","A#4","B4","C5","C#5","D5","D#5","E5","F5","F#5","G5","G#5",
              "A5","A#5","B5"{- ... -}]

pianoFreq x = 435 * 1.0594630943593 ** ((fromIntegral x) - 49)

getPianoFreq x = maybe 8000 (pianoFreq . (+ 1)) (elemIndex x pianoNotes)

t x = tone (getPianoFreq x) 2000 1.0

main :: IO ()
main = do
  let notesl =["D2",
               "D3",
               "B2",
               "F2",
               "B2",
               "B1",
               "C2",
               "D2",
               "E2"]
  let notes = ["##", "G3", "A3",
               "B3", "D4", "C4",
               "C4", "E4", "D4", -- from D4
               "D4", "G4", "F4",
               "G4", "D4", "C4",
               "G3", "A3", "B3",
               "C4", "D4", "E4",
               "D4", "C4", "B3",
               "A3", "B3", "G3"] -- end
{--               "F3", "G3", "A3",
               "D3", "F3", "A3",
               "C4", "B3", "A3",
               "B3", "G3", "A3",
               "B3", "D4", "C4",
               "C4", "E4", "D4",
               "D4", "G4", "F4",
               "G4", "D4", "B3",
               "G3", "A3", "B3"]-}
--               "E3", "D4", "C4"
--               ]
  let blank = t "##"
  let strs = concat (map t notes)
  let strsl = concat (map (\ x -> (concat (replicate 5 (t x))) ++ blank) notesl)
  let bytes = map chr (zipWith (+) strs strsl)
  hPutStr stdout bytes

Name: Anonymous 2009-12-14 17:38

http:.//iwantsicp.com

Name: Anonymous 2009-12-14 21:36

>>56
Stop using the word "wavetable" wrong.  Wavetable-based sound is not the same thing as sample-based sound.

Name: Anonymous 2009-12-14 21:57

SAMPLE MY ANUS

Name: Anonymous 2009-12-14 22:23

>>70
Oh look, you are retarded enough.

Newer Posts
Don't change these.
Name: Email:
Entire Thread Thread List