Einen Akkord programmieren



  • Hallo,
    ich habe in Java einen Sound-Generator programmiert, der im Grunde eine Math. Funktion nimmt und daraus einen Bytestream erstellt, multipliziert mit der Amplitude,
    wenn sich jemand dafuer interessiert, hier ist der Code:

    /**
         * Generate and returns one sample of the data as a byte array.
         */
        def generate() {
            float fAmplitude = (float) (amplitude * Math.pow(2, sampleSizeInBits - 1));
            // length of one period in frames
            int nBufferLength = periodLengthInFrames * frameSize;
            def data = new byte[nBufferLength];
            for (int nFrame = 0; nFrame < periodLengthInFrames; nFrame++) {
                /**
                 * The relative position inside the period of the waveform. 0.0 =
                 * beginning, 1.0 = end
                 */
                float fPeriodPosition = (float) nFrame / (float) periodLengthInFrames;
                float fValue = calculateValue(fPeriodPosition)
                int nValue = Math.round(fValue * fAmplitude);
                int nBaseAddr = (nFrame) * frameSize;
                // this is for 16 bit stereo, little endian
                data[nBaseAddr + 0] = (byte) (nValue & 0xFF);
                data[nBaseAddr + 1] = (byte) ((nValue >>> 8) & 0xFF);
                data[nBaseAddr + 2] = (byte) (nValue & 0xFF);
                data[nBaseAddr + 3] = (byte) ((nValue >>> 8) & 0xFF);
            }
    
            return data
        }
    

    Das generiert mir z.B. eine 5 Sekunden lange, 400Hz Sinus Welle.
    Wie kann man das ganze so modifizieren, dass ich ein Akkord kriege?

    Also, so wie ich das verstanden habe ist ein Akkord nichts weiter als 2 oder mehrere Schwingungen, die zusammen moduliert werden. Kann ich also mehrere Sinus Wellen mit unterschiedlicher Frequenz erstellen und die dann irgendwie modulieren?

    Wie sieht das programmiertechnisch aus? Hat jemand eine Idee oder ein Tutorial, Beispielcode?



  • ^^mir fällt auf, dass da nirgends die sinus-funktion benutzt wird. kriegste wirklich 'ne sinuswelle raus?

    btw, ich hab zufälligerweise das, was du suchst:

    /**
         * Generates wave object of multiple sine curves
         * @param samplingrate The sampling rate
         * @param freq         array of frequencies
         * @param samples      Number of samples to generate
         * @return Wave16 object with all frequencies
         */
        public Wave16 curveSine(@ParamDesc("Sampling rate")int samplingrate,
                                @ParamDesc("Array of frequencies")int[] freq,
                                @ParamDesc("Number of samples")int samples)
        {
            Wave16 out = new Wave16(samples, samplingrate);
    
            for (int x = 0; x < samples; x++)
            {
                double f = 0;
                for (int aFreq : freq)
                {
                    f = f + (Wave16.MAX_VALUE * Math.sin(2 * x * Wave16.PI / samplingrate * aFreq));
                }
                out.data[x] = f / freq.length;
            }
            out.data = Wave16.fitValues(out.data);
            return out;
        }
    

    ^^also vom prinzip her einfach die werte der sinusse aufaddieren.
    🙂



  • ;fricky schrieb:

    ^^mir fällt auf, dass da nirgends die sinus-funktion benutzt wird. kriegste wirklich 'ne sinuswelle raus?

    Wer braucht denn sowas langweiliges wie n Sinus? Ne lustige Rechteckkurve oder Sägezahnkurve klingt doch gleich viel ansprechender 😉



  • pumuckl schrieb:

    Wer braucht denn sowas langweiliges wie n Sinus? Ne lustige Rechteckkurve oder Sägezahnkurve klingt doch gleich viel ansprechender

    bist wohl techno-fan der härteren gangart *fg*
    🙂



  • Sowas wie sin versteht doch kein Mensch. Sprechende Namen sind lange Namen, wie z.B.

    DEvent schrieb:

    calculateValue



  • DEvent schrieb:

    Kann ich also mehrere Sinus Wellen mit unterschiedlicher Frequenz erstellen und die dann irgendwie modulieren?

    Wie sieht das programmiertechnisch aus? Hat jemand eine Idee oder ein Tutorial, Beispielcode?

    Addieren. Das Stichwort heißt addieren. Z.B. sin(440 Hz * t) + sin(440 Hz * 2^(4/12) * t ) + sin(440 Hz * 2^(7/12) * t) ist ein dur-akkord. A Dur. wenn du 4/12 durch 3/12 ersetzt, ein Moll-Akkord. Allgemeiner: eine Multiplikation mit 2^(n/12) ist eine Translation um n Halbtöne. Verschiedene Töne können addiert werden. (Denn die Fouriertransformation ist linear.)



  • Bashar schrieb:

    Sowas wie sin versteht doch kein Mensch. Sprechende Namen sind lange Namen, wie z.B.

    DEvent schrieb:

    calculateValue

    Hehe. Ganz besonders weil calculateValue() eine abstrakte Methode ist, die nach implementierung eben eine Sin/Saegezahn/3-Eck/4-Eck Funktion ist.

    Aber danke, also einfach aufaddieren 👍



  • Wenn es wie ein bestimmtes Instrument klingen soll musst du dazu noch die passenden Obertöne (also die gleichen Frequenzen * n) dazuaddieren. Wenn ich mich richtig entsinne waren es bei Blaßinstrumenten vor allem Obertöne ungerader Ordnung und bei Saiteninstrumenten Obertöne mit gerader Ordnung.



  • Storm.Xapek.de schrieb:

    Wenn es wie ein bestimmtes Instrument klingen soll musst du dazu noch die passenden Obertöne (also die gleichen Frequenzen * n) dazuaddieren. Wenn ich mich richtig entsinne waren es bei Blaßinstrumenten vor allem Obertöne ungerader Ordnung und bei Saiteninstrumenten Obertöne mit gerader Ordnung.

    und noch 'ne passende, sogenannte 'ADSR-hüllkurve' drüberlegen.
    🙂



  • Storm.Xapek.de schrieb:

    Wenn es wie ein bestimmtes Instrument klingen soll musst du dazu noch die passenden Obertöne (also die gleichen Frequenzen * n) dazuaddieren. Wenn ich mich richtig entsinne waren es bei Blaßinstrumenten vor allem Obertöne ungerader Ordnung und bei Saiteninstrumenten Obertöne mit gerader Ordnung.

    http://cnx.org/content/m12589/latest/

    heutzutage (so seit 25 jahren) macht man aber coolere sachen
    http://lab.andre-michelle.com/karplus-strong-guitar
    http://en.wikipedia.org/wiki/Karplus-Strong_string_synthesis



  • ^^alter hut: http://www.falstad.com/dfilter/
    (filter-typ auf 'plucked string' stellen)
    🙂



  • Kann mir jemand noch ein wenig weiter helfen? Irgendwie verstehe ich das ganze nicht.
    Also wenn ich 3 Frequenzen habe, wie kann die zu einem Akkord zusammenfuehren? Also z.B.

    frequenzen = [400.0, 500.0, 600.0];
    float akkord;
    for (float freq : frequenzen) {
        akkord = ...??
    }
    


  • DEvent schrieb:

    Also wenn ich 3 Frequenzen habe, wie kann die zu einem Akkord zusammenfuehren?

    von allen 3 frequenzen ein sample berechnen, alles addieren und abspeichern. dann das das nächste sample usw. oben hab ich 'ne funktion gepostet, die genau das macht (mit sinussen).
    🙂



  • ;fricky schrieb:

    DEvent schrieb:

    Also wenn ich 3 Frequenzen habe, wie kann die zu einem Akkord zusammenfuehren?

    von allen 3 frequenzen ein sample berechnen, alles addieren und abspeichern. dann das das nächste sample usw. oben hab ich 'ne funktion gepostet, die genau das macht (mit sinussen).
    🙂

    Mein Generator ist darauf ausgelegt aus einer Frequenz die samples zu erzeugen. Kann man also aus 3 Frequenzen eine Frequenz berechnen, die den Akkord representiert?

    Also so z.B.

    frequenzen = [400.0, 500.0, 600.0];
    
    float getAkkordFrequenz(List frequenzen) {
        float akkord;
        for (float freq : frequenzen) {
            akkord = ...??
        }
        return akkord;
    }
    
    // erstellt den byte-stream aus den von getAkkordFrequenz()
    // berechneten Akkord
    byte[] getSamples(float frequenz) {
        // mit sinus und so
    }
    


  • DEvent schrieb:

    Kann man also aus 3 Frequenzen eine Frequenz berechnen, die den Akkord representiert?

    nee, ein akkord besteht aus mehreren tönen (normalerweise 3), daraus kannste nicht eine frequenz machen.
    beispiel: http://img402.imageshack.us/img402/3549/unbenanntzx.jpg
    (300, 400 und 500 Hz)



  • ;fricky schrieb:

    DEvent schrieb:

    Kann man also aus 3 Frequenzen eine Frequenz berechnen, die den Akkord representiert?

    nee, ein akkord besteht aus mehreren tönen (normalerweise 3), daraus kannste nicht eine frequenz machen.
    beispiel: http://img402.imageshack.us/img402/3549/unbenanntzx.jpg
    (300, 400 und 500 Hz)

    Danke, jetzt verstehe ich.
    Wie kann man den berechnen wieviele samples man fuer eine volle Schwing braucht?
    Z.b. bei den Frequenzen 300, 400 und 500 wiederholt sich die Schwingung bei samples ca. 882

    Bei einer normalen Sinuswelle ist es
    samples = samplingRate / frequency
    Bei einer samplingRate von 44100Hz und einer Frequenz von 300Hz sind es 147 samples. Und wie berechnet man das bei einem Akkord von x Frequenzen?



  • DEvent schrieb:

    Wie kann man den berechnen wieviele samples man fuer eine volle Schwing braucht?

    ganz einfach: anzahl_samples = samplingrate/frequenz. also z.b. bei 'ner samplingrate von 22050 samples/s und einer frequenz von 1000Hz bekommste 22050/1000 = 23(aufgerundet) samples für eine volle schwingung.
    🙂



  • ;fricky schrieb:

    DEvent schrieb:

    Wie kann man den berechnen wieviele samples man fuer eine volle Schwing braucht?

    ganz einfach: anzahl_samples = samplingrate/frequenz. also z.b. bei 'ner samplingrate von 22050 samples/s und einer frequenz von 1000Hz bekommste 22050/1000 = 23(aufgerundet) samples für eine volle schwingung.
    🙂

    Und bei einem Akkord von 3 Frequenzen?



  • DEvent schrieb:

    Und bei einem Akkord von 3 Frequenzen?

    versuch doch mal die samples für jede frequenz einzeln auszurechnen und berechne dann das kleinste gemeinsame vielfache. das dürfte der erste gemeinsame nulldurchgang nach dem start sein. was gescheiteres fällt mir jetzt auch nicht ein.
    🙂



  • so müsste es richtig gehen: http://www.physik.uni-kl.de/ziegler/Skripte/Exphys-BC-4_1-4_3.pdf
    (ab seite 66, verschiedene frequenzen, schwebung)
    🙂



  • ;fricky schrieb:

    DEvent schrieb:

    Und bei einem Akkord von 3 Frequenzen?

    versuch doch mal die samples für jede frequenz einzeln auszurechnen und berechne dann das kleinste gemeinsame vielfache. das dürfte der erste gemeinsame nulldurchgang nach dem start sein. was gescheiteres fällt mir jetzt auch nicht ein.
    🙂

    Das ist korrekt. Wenn es kein gemeinsames vielfaches außer 0 gibt (wie bei eigentlich jedem akkord in einer wohltemperierten stimmung) gibt es auch keine minimale samplezahl. in anderen stimmungen, in denen die verhältnisse der frequenzen immer rationale zahlen sind, geht das. Das ausrechnen der Schwebungsfrequenz reicht nicht aus, da die schwingung nicht zwingend translationsinvariant mit der periode der schwebungsfrequenz ist. (es mag aber eine gute näherung sein... )


Anmelden zum Antworten