Forum: PC-Programmierung Synthesizer programmieren


von Sam .. (sam1994)


Angehängte Dateien:

Lesenswert?

Hi

Ich versuche gerade einen Synthesizer für einen Tiny/Mega (je nach dem 
wie groß der am Ende wird) zu programmieren. Um das zu testen hab ich 
das erstmal am PC probiert. Bisher kann man bis zu 255 Kanäle nutzen. 
Töne hab ich bisher noch nicht definiert. Man kann nur eine Frequenz 
einstellen (44100 / x).

Problem ist nur die Lautstärke. Sobald die Lautstärken unterschiedlich 
sind oder auch bei bestimmten einstellungen, hört man ein Knarren.

Der ganze Code ist im Anhang. Alleg44.dll braucht man um die Exe 
auszuführen.
1
struct Tone
2
{
3
    unsigned char pwm;
4
    unsigned char max;
5
    unsigned char volume;
6
    unsigned short len;
7
};
8
9
struct Stream
10
{
11
    Tone* stream;
12
    unsigned char len;
13
    unsigned char streampos;
14
    unsigned char tonepwmpos;
15
    unsigned short tonepos;
16
};
17
18
struct PolyStream
19
{
20
    Stream* stream;
21
    unsigned char len;
22
    unsigned char loglen;   
23
};
24
25
unsigned char GetPWM(PolyStream* stream)
26
{
27
    unsigned char i = stream->len - 1;
28
    unsigned short pwm = 0;
29
    do
30
    {
31
        pwm += GetTone(&(stream->stream[i]));
32
    }
33
    while(i--);
34
    pwm >> stream->loglen;
35
    return (unsigned char)pwm;
36
}
37
38
unsigned char GetTone(Stream* stream)
39
{
40
    if(++stream->tonepos == stream->stream[stream->streampos].len) //Ton zu Ende?
41
    {
42
        stream->tonepos = 0;    //Werte zurücksetzen
43
        stream->tonepwmpos = 0;
44
        stream->streampos++;   //nächster Ton
45
    }
46
    if(stream->streampos >= stream->len)
47
        return 128;
48
    if(stream->stream[stream->streampos].pwm > ++stream->tonepwmpos)
49
    {
50
        return stream->stream[stream->streampos].volume;
51
    }
52
    else
53
        if(stream->tonepwmpos == stream->stream[stream->streampos].max)
54
        {
55
            stream->tonepos++;
56
            stream->tonepwmpos = 0;
57
        }
58
    return 255 - stream->stream[stream->streampos].volume;
59
}
Das ist der Synthesizer abschnitt. Hier müsste der Fehler sein, den ich 
nicht finde.

Es ist doch nichts anderes als, Frequenzen erzeugen und Mittelwert 
bilden?

Anmerkung zum Code: Ich habe extra unsigned char und ushort genutzt, da 
ich das am Ende auf dem µC auch machen muss.

EDIT:
Ist gelöst. Es lag am schieben. Ich habe keine Zuweisung beim schieben 
gemacht.

von Sam .. (sam1994)


Angehängte Dateien:

Lesenswert?

Läuft jetzt ganz gut. Obwohl es nur 8 bit sind hört es sich ganz gut an. 
Hab noch einen Konverter geschrieben, so schlecht ist die Quali gar 
nicht.

Ich würde noch gerne ein paar Drums dazumachen, aber wie soll ich das 
anstellen? Ich hab ja gar keine Samples dafür. Lässt sich das vielleicht 
auch "synthetisch" herstellen. Also mit irgendeiner besonderen 
Schwingung?

Ein bessere Midi-Eingabemöglichkeit möchte ich noch programmieren, das 
jetzige ist nur zum testen. Der Konverter soll am Ende nur ein Array 
erstellen. Das wird wahrscheinlich auch das nächste was ich machen 
werde, denn das Kompilieren dauert ewig.

Das einzige brauchbare Projekt zum Midi einlesen, das ich auf die 
Schnelle fand war das hier: 
http://www.codeproject.com/KB/audio-video/MIDIToolkit.aspx

Leider muss man da die Midi-Datei einmal abspielen um sie zu 
konvertieren. Und da das ganze gar nicht dafür gadacht ist, muss man 
Zeitmessungen machen um die Zeiten zu bekommen (sehr ineffizient). Wenn 
jemand eine bessere Lib kennt, wäre mir sehr geholfen.

Eine Hörprobe hab ich mal hochgeladen. Immernoch diesselbe 
Rechteckschwingung, diesmal aber mit Tönen und mit einer konvertierten 
Midi-Datei.

Die Töne sind zum Teil schief, da die Steuerung nicht genau genug ist. 
Da müsste man sich was einfallen lassen.

Eine Frage hätte ich dann noch:
Was heißt das : _mcleanup tos overflow
Das steht bei mir in der Console nach dem Beenden des Programms

von Sam .. (sam1994)


Angehängte Dateien:

Lesenswert?

Hier noch mein bescheidener Konverter.

von Sam .. (sam1994)


Angehängte Dateien:

Lesenswert?

Samuel K. schrieb:
> Hier noch mein bescheidener Konverter.

Mit ein Haufen kleiner Bugs. Diese Version kann endlich ohne Probleme 
konvertieren.
Leider erstellt der Konverter bei manchen Stücken >1000 Kanäle was total 
unsinnig ist und deshalb nicht funktioniert.

von Mark B. (markbrandis)


Lesenswert?

Samuel K. schrieb:
> Ich würde noch gerne ein paar Drums dazumachen, aber wie soll ich das
> anstellen? Ich hab ja gar keine Samples dafür. Lässt sich das vielleicht
> auch "synthetisch" herstellen. Also mit irgendeiner besonderen
> Schwingung?

Z.B. weißes Rauschen als Ausgangsmaterial und dann ein (Tiefpass- etc.) 
Filter drauf (subtraktive Synthese).

http://de.wikipedia.org/wiki/Subtraktive_Synthese

von Mirko (Gast)


Lesenswert?

Sound on Sound ( http://www.soundonsound.com ) hatte mal eine Serie von 
Artikeln über Synthese verschiedener Instrumente. Such da mal nach 
"Synth Secrets", sind auch Drums und Percussion dabei.

Irgendwann wollte ich sowas auch noch mal umsetzen, aber man kommt ja zu 
nichts...

Mirko

von Sam .. (sam1994)


Lesenswert?

Danke für die Links. Ich muss mich da mal einlesen.

Das andere Eingabeformat hab ich jetzt programmiert.

Auszug aus meinem Konverter, der leider noch nicht richtig funktioniert:
1
             * HEADER
2
             * Anzahl Kanäle (1 - 255)
3
             * Anzahl der Noten/Befehle von Kanal 1-x (1 - 65535)
4
             * 
5
             * DATA
6
             * Alle Noten/Befehls - Byte von Kanal 1-x
7
             * 
8
             * 
9
             * Beispiel
10
             * 2 Kanäle
11
             * 3 Noten/Befehle im 1. Kanal
12
             * 1 Noten/Befehle im 2. Kanal
13
             * a 1. Note/Befehl des 1. Kanals
14
             * b 2. Note/Befehl
15
             * c 3. Note/Befehl
16
             * d 1. Note/Befehl des 2. Kanals
17
             * 
18
             * entspricht {2,3,1,a,b,c,d}

Mein Konverter baut gerade völligen Mist, deshalb sind im MidiTest nur 
12 Töne aus Handarbeit. Gibt es eingentlich ein 
Opensource-Midiconverter/Analyser?

Wie viel Kanäle haltet ihr auf einem Attiny für realistisch? Ich finde 
das wird schon ein bisschen knapp: Mit einem Bauratenquarz mit 22.12Mhz 
kommt man auf 22.12Mhz / 44100 = ~500 Takte
Da kann man den PWM-Channel 2 mal durchlaufenlassen. In 500 Takten muss 
man dann das hier für alle Kanäle neuberechnet haben:
1
unsigned char GetChannel(unsigned char i)
2
{
3
    if(channel[i].pos >= channel[i].len)
4
        return 128;
5
    if(++channel[i].tonepos >= channel[i].tonelen)
6
    {
7
        channel[i].tonepos = 0;
8
        channel[i].freqpos = 0;
9
        //Neuer Ton
10
        unsigned char value;
11
        while(!IsTone(value = array[++channel[i].pos]))
12
        {
13
            switch(value & 0xC0)
14
            {
15
                case 0xC0: channel[i].tonelen = (1 << (7 - (value & 0x07))) * 44100 / 128 * 2;
16
                    printf("Channel %d (%d / %d): New Tone-Len: %d\n",i,channel[i].pos, channel[i].len, channel[i].tonelen);
17
                    break;
18
                default: printf("Channel %d (%d / %d): Error: Unknown command: %d\n",i,channel[i].pos, channel[i].len, value & 0xC0);
19
            };
20
        }
21
        
22
        channel[i].freq = Freq[array[channel[i].pos]];
23
        printf("Channel %d (%d / %d): New Tone: %d\n", i,channel[i].pos, channel[i].len,array[channel[i].pos]);
24
    }
25
    if(++channel[i].freqpos >= channel[i].freq)
26
        channel[i].freqpos = 0;
27
    else
28
    {
29
        if(channel[i].freqpos > channel[i].freq / 2)
30
            return 255 - channel[i].tonevol;
31
        return channel[i].tonevol;
32
    }
33
}

Für den µC werd ich natürlich versuchen es noch ein bisschen zu 
optimieren. Wahrscheinlich muss man es am Ende sowieso in Asm umsetzen.

von Sam .. (sam1994)


Angehängte Dateien:

Lesenswert?

Verdammt, schon wieder den ,Anhang vergessen.

von Christoph H. (mc-entwickler)


Lesenswert?

Hier ein paar Tipps.

Atmega Töne in Assembler:
http://www.linusakesson.net/scene/craft/index.php
( 4 Kanäle )
Hier gibt es eine schöne Link-Liste:
http://www.mikrocontroller.net/articles/Klangerzeugung

3 Kanäle in C:
http://www.arduino.cc/playground/Main/SID-shield

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.