Discussion:
Steigung des Sinus - Audiosynthese
(zu alt für eine Antwort)
kosst amojan
2007-09-29 18:31:20 UTC
Permalink
Moin,

Ich möchte ein Audiosignal erzeugen. Und zwar soll
das ein einfaches Sinussignal werden.

Der springende Punkt ist, dass sich die Frequenz nach
einer gewissen Zeit "sprungartig" ändern soll.

Die Amplitude soll immer gleich hoch sein.

Also haben wir eine simple Funktion wie
y=sin((t*b)+d) mit t = zeitpunkt, b = Breitefaktor, d=Phasenverschiebung.
Oder so ähnlich zumindest...

Da es sich um ein Audiosignal handeln soll,
ist alles etwas einfacher, denn es sind nur 4096 Datenpunkte
zu füllen.

Beispielsweise existiert bis
Punkt 1001 eine Sinusfunktion, welche 440 Hz erzeugt.
Ab Punkt 1002 soll die Frequenz schlagartig
auf z.B. 345 Hz geändert werden _ohne_ ein Knacksen
zu erzeugen. Das bedeutet die Steigung/Frequenzänderung
darf keine Sprünge aufweisen/erzeugen.

Also errechne ich mir die Steigung aus der Gleichung für
die 440Hz, welche auf Grund der 440Hz im Punkt 1002
vorhanden sein müsste.

Jetzt meine frage: Wie erstellt mann eine Sinusfunktion,
die so verschoben und gestreckt ist, dass die Steigung
im Punkt 1002 zum vorigen Signal nahtlos anschließt?

Ich hoffe mein Problem ist einigermaßen klar.


Gruß,

Markus
Robin Koch
2007-09-29 19:08:30 UTC
Permalink
Post by kosst amojan
Der springende Punkt ist, dass sich die Frequenz nach
einer gewissen Zeit "sprungartig" ändern soll.
Also haben wir eine simple Funktion wie
y=sin((t*b)+d) mit t = zeitpunkt, b = Breitefaktor, d=Phasenverschiebung.
Oder so ähnlich zumindest...
[...]
Post by kosst amojan
Jetzt meine frage: Wie erstellt mann eine Sinusfunktion,
die so verschoben und gestreckt ist, dass die Steigung
im Punkt 1002 zum vorigen Signal nahtlos anschließt?
Naja, da die Frequenz ("Breitenfaktor") deines neuen Signals feststeht
(ebenso wie die Amplitude) lässt sich sinnvollerweise nur noch die
Phasenverschiebung beeinflußen, oder?

Die Steigung des ersten (z.B.: sin(440*2*PI*t)+0) Signals im Punkt 1002
kannst Du ja berechnen. Und dann suchst Du das d, für das
sin(345*2*PI*t)+d in der Stelle t=1002 die gleiche Ableitung hat. d
kommt dann aus [0, 1/345).

Oder habe ich etwas falsch verstanden?
--
Robin Koch
np: Bomfunk MC's feat. Jessica Folcker - (Crack It) Something going on
Zungenbrecher Nr. 11: "Mehrere manchmal merkwürdige Minestranten meinen,
manche Ministerien müssten mal mysteriösen Müll
minuziös mit mystischem Mist mischen."
kosst amojan
2007-09-29 19:28:08 UTC
Permalink
"Robin Koch"
Post by kosst amojan
Der springende Punkt ist, dass sich die Frequenz nach
einer gewissen Zeit "sprungartig" ändern soll.
Also haben wir eine simple Funktion wie
y=sin((t*b)+d) mit t = zeitpunkt, b = Breitefaktor, d=Phasenverschiebung.
Oder so ähnlich zumindest...
[...]
Post by kosst amojan
Jetzt meine frage: Wie erstellt mann eine Sinusfunktion,
die so verschoben und gestreckt ist, dass die Steigung
im Punkt 1002 zum vorigen Signal nahtlos anschließt?
Naja, da die Frequenz ("Breitenfaktor") deines neuen Signals feststeht (ebenso wie die Amplitude) lässt sich sinnvollerweise nur
noch die Phasenverschiebung beeinflußen, oder?
Die Steigung des ersten (z.B.: sin(440*2*PI*t)+0) Signals im Punkt 1002 kannst Du ja berechnen. Und dann suchst Du das d, für das
sin(345*2*PI*t)+d in der Stelle t=1002 die gleiche Ableitung hat. d kommt dann aus [0, 1/345).
Oder habe ich etwas falsch verstanden?
Jein.

Die Steigung muss ja nicht an einem Zeitpunkt t gegeben sein,
sondern auch in der Höhe des Punktes passen. Da liegt mein Problem.

Extremeres Beispiel. Von 10000 Hz auf 100Hz. Nehmen wir an
die Frequenzänderung findet statt, wenn die Amplitude gerade
fällt und sich bei 0,5 befindet bei einem Amplitudenmaximum von 1.
IMHO gibt es diese Steigung in einem 100 Hz Signal gar nicht.
Ich seh momentan den Wald vor lauter Bäumen nicht mehr.

Die einzige Steigung die bei ALLEN Frequenzen vorhanden ist, ist doch
die Steigung 0 beim Amplitudenmaximum. Ist die einzige sinnvolle Möglichkeit
denn wirklich grundsätzlich bis zum nächsten Amplitudenmaximum zu warten und
erst ab dort eine Frequenzänderung zu machen? Irgendwie beschleicht mich das
Gefühl dass das resultat dann besch.... klingen wird :(
Robin Koch
2007-09-29 19:55:09 UTC
Permalink
Die Steigung muss ja nicht an einem Zeitpunkt t gegeben sein, sondern
auch in der Höhe des Punktes passen. Da liegt mein Problem.
Stimmt. :-/

Dann würde ich auch sagen, daß das einfachste (und womöglich einzig
sinnvolle) tatsächlich ist auch das nächste Extremum zu "warten". (So es
denn in einen der 4096 Punkte fällt.)
Irgendwie beschleicht mich das Gefühl dass das resultat dann
besch.... klingen wird :(
Wieso sollte es groß anders klingen, als wenn Du den Übergang eine
tausenstel Sekunde früher machen würdest?
--
Robin Koch
np: Die ?Ärzte - El Cattivo (live)
Der Gemeine strebt nach Gleichheit.
Der Edle strebt nach Harmonie. - (nach Konfuzius)
f***@schaudel.com
2007-09-30 08:07:29 UTC
Permalink
Post by kosst amojan
Jetzt meine frage: Wie erstellt mann eine Sinusfunktion,
die so verschoben und gestreckt ist, dass die Steigung
im Punkt 1002 zum vorigen Signal nahtlos anschließt?
Ich hoffe mein Problem ist einigermaßen klar.
Das Problem ist viel einfacher als Du denkst, da Deine Grundannahme
falsch ist:
Ein "Knacksen" im Audiosignal hörst Du dann, wenn die Amplitudenkurve
nicht stetig ist.
Die Ableitung der Amplitudenkurve braucht nicht unbedingt stetig zu
sein. Kannst Du Dir einfach daran überlegen, dass ein Dreiecksignal ja
auch nicht nur eine Abfolge von "Knacksern" ist...

Deswegen kannst Du einfach irgendwo mit der neuen Frequenz weiter
machen und wirst kein knacksen erzeugen...

Gruss,
Florian
kosst amojan
2007-09-30 08:21:28 UTC
Permalink
Post by f***@schaudel.com
Post by kosst amojan
Jetzt meine frage: Wie erstellt mann eine Sinusfunktion,
die so verschoben und gestreckt ist, dass die Steigung
im Punkt 1002 zum vorigen Signal nahtlos anschließt?
Ich hoffe mein Problem ist einigermaßen klar.
Das Problem ist viel einfacher als Du denkst, da Deine Grundannahme
Ein "Knacksen" im Audiosignal hörst Du dann, wenn die Amplitudenkurve
nicht stetig ist.
Die Ableitung der Amplitudenkurve braucht nicht unbedingt stetig zu
sein. Kannst Du Dir einfach daran überlegen, dass ein Dreiecksignal ja
auch nicht nur eine Abfolge von "Knacksern" ist...
Deswegen kannst Du einfach irgendwo mit der neuen Frequenz weiter
machen und wirst kein knacksen erzeugen...
Ähm.. Jetzt nochmal auf Deutsch um zu sehen ob ich dich richtig
verstanden habe:

Meinst du damit, ich soll einfach nur die neue Frequenz so schieben,
dass sie lediglich mit der alten Frequenz am entscheidenden Punkt
in der aktuellen Amplitudenhöhe zusammenpasst?

Das könnte natürlich gehen. Wenn man dann noch abfallend und steigend
erkennt und entsprechend fortsetzt...

Ich glaube so werde ich es einfah machen. Eine andere Chance sehe ich kaum,
außer dass man einen gleitenden FFT-Buffer über den Schnittbereich bewegen könnte
und somit den Knacks entfernen können müsste, aber das ersheint mir für so einen
Zweck etwas Overkill zu sein.

Gruß,

Markus
Jens Dierks
2007-09-30 10:10:40 UTC
Permalink
Post by kosst amojan
Meinst du damit, ich soll einfach nur die neue Frequenz so schieben,
dass sie lediglich mit der alten Frequenz am entscheidenden Punkt
in der aktuellen Amplitudenhöhe zusammenpasst?
Das könnte natürlich gehen. Wenn man dann noch abfallend und steigend
erkennt und entsprechend fortsetzt...
Ich glaube so werde ich es einfah machen. Eine andere Chance sehe ich kaum,
außer dass man einen gleitenden FFT-Buffer über den Schnittbereich bewegen könnte
und somit den Knacks entfernen können müsste, aber das ersheint mir für so einen
Zweck etwas Overkill zu sein.
Noch einfacher:
y=sin(phi)
und für jeden neuen Wert verschiebst du phi um delta_phi, welches
du für die nötige Frequenz berechnest.
Wenn du eine neue Frequenz brauchst, musst du nur delta_phi ändern,
die absolute Phase bleibt ja erhalten.
Du kannst auch delta_phi langsam über x Werte an den neuen Wert
anpassen, dann wird auch der kleine Knick abgerundet. Ist zwar kein
optimierter lowpass wie bei der FFT, aber ein Aufwand nahe bei null.

Jens
Andreas Micheler
2007-09-30 20:11:43 UTC
Permalink
Hallo Markus,

das Problem läßt sich einfach lösen,
indem man entweder auf die stetige Steigung verzichtet,
oder einen einfachen Filter auf das berechnete Audiosignal anwendet,
wie bereits von Florian und Jens gepostet.

Das folgende aUCBLogo-Programm berechnet nach dieser einfachen Methode
eine chromatische Tonleiter und spielt den Sound oder stellt ihn
graphisch dar.
Knacksen ist dabei nicht wahrnehmbar, d.h. die Methode funktioniert.


to makewav_sines
rate=44100
ntones=13
size=Int rate*ntones/8
wavHeaderType=(list
[ChunkID word RIFF]
[wavfilesize int]
[RIFFtype word 4] ;the last item is the string length

[formatChunkID word fmt\ ]
[formatChunkSize int 16]
[compressionCode int16 1]
[NumberOfChannels int16 1]
(list "SampleRate "int rate)
(list "BytesPerSecond "int rate*2)
[BlockAlign int16 2]
[BitsPerSample int16 16]

[DataChunkID word data]
(list "DataChunkSize "int size*2)
)
wavHeader=struct wavHeaderType
wavHeaderSize=SizeOf wavHeader
wavHeaderSizeHalf=int wavHeaderSize/2
wavsize=wavHeaderSize+size*2
wavHeader'RIFFtype=[WAVE] ;example for setting a string
wavHeader'wavfilesize=wavsize
; pr wavHeader
wav=Int16Array int wavsize/2
setWriter wav
typeBin wavHeader
setWriter []
; setReader wav
; wh=readStructBin wavHeaderType
; pr wh
; setReader []
ssize=Int size/ntones-1
phi=0
t=0
t0=0
dt=1/rate
k=wavHeaderSizeHalf+1
for [i 0 ntones-1]
[ f=440*2^(i/12)
for [j 0 ssize]
[ t=t+dt
phi=phi+f*(t-t0)
t0=t
wav.k=Int16 30000*(sin 360*phi)
k=k+1
]
]
; drawPlot
playWave wav 0
end

to drawPlot
WindowMode
hideTurtle
clearScreen
PenUp
setXY -400 0
PenDown
setXY rseqfa -400 400 Int wavsize/2 FloatArray wav
updateGraph
end


Schönen Gruß,
Andreas
Andreas Micheler
2007-09-30 20:13:21 UTC
Permalink
Hallo Markus,

das Problem läßt sich einfach lösen,
indem man entweder auf die stetige Steigung verzichtet,
oder einen einfachen Filter auf das berechnete Audiosignal anwendet,
wie bereits von Florian und Jens gepostet.

Das folgende aUCBLogo-Programm berechnet nach dieser einfachen Methode
eine chromatische Tonleiter und spielt den Sound
oder stellt ihn graphisch dar (Strichpunkt vor drawPlot entfernen).
Knacksen ist dabei nicht wahrnehmbar, d.h. die Methode funktioniert.


to makewav_sines
rate=44100
ntones=13
size=Int rate*ntones/8
wavHeaderType=(list
[ChunkID word RIFF]
[wavfilesize int]
[RIFFtype word 4] ;the last item is the string length

[formatChunkID word fmt\ ]
[formatChunkSize int 16]
[compressionCode int16 1]
[NumberOfChannels int16 1]
(list "SampleRate "int rate)
(list "BytesPerSecond "int rate*2)
[BlockAlign int16 2]
[BitsPerSample int16 16]

[DataChunkID word data]
(list "DataChunkSize "int size*2)
)
wavHeader=struct wavHeaderType
wavHeaderSize=SizeOf wavHeader
wavHeaderSizeHalf=int wavHeaderSize/2
wavsize=wavHeaderSize+size*2
wavHeader'RIFFtype=[WAVE] ;example for setting a string
wavHeader'wavfilesize=wavsize
; pr wavHeader
wav=Int16Array int wavsize/2
setWriter wav
typeBin wavHeader
setWriter []
; setReader wav
; wh=readStructBin wavHeaderType
; pr wh
; setReader []
ssize=Int size/ntones-1
phi=0
t=0
t0=0
dt=1/rate
k=wavHeaderSizeHalf+1
for [i 0 ntones-1]
[ f=440*2^(i/12)
for [j 0 ssize]
[ t=t+dt
phi=phi+f*(t-t0)
t0=t
wav.k=Int16 30000*(sin 360*phi)
k=k+1
]
]
; drawPlot
playWave wav 0
end

to drawPlot
WindowMode
hideTurtle
clearScreen
PenUp
setXY -400 0
PenDown
setXY rseqfa -400 400 Int wavsize/2 FloatArray wav
updateGraph
end


Schönen Gruß,
Andreas
Wolfgang Draxinger
2007-10-01 11:34:52 UTC
Permalink
Post by kosst amojan
Moin,
Ich möchte ein Audiosignal erzeugen. Und zwar soll
das ein einfaches Sinussignal werden.
Der springende Punkt ist, dass sich die Frequenz nach
einer gewissen Zeit "sprungartig" ändern soll.
Die meisten auf diesem Gebiet unbedarften Leute machen den Fehler
bei der Audiosynthese den Oszillator als

a(t) = A * sin(\omega * t + \theta)

zu beschreiben, d.h. die Zeit wird als einzige Veränderliche
betrachtet. Wenn nun \omega eigentlich \omega(t) ist und nicht
stetig bekommt man natürlich ein Problem, da die Verkettung
einer nicht stetigen mit einer stegigen wieder nicht stetig ist.

Stattdessen geht man bei der Audiosynthese so vor, dass man von
einem konstanten \Delta t ausgeht (der Samplingperiode) und über
diese inkrementell die Phase weiterschiebt, d.h.

\phi_0 = 0
\phi_{t+\Delta t} = \phi_t + \omega(t) * \Delta_t

Für den Grenzübergang \Delta t -> 0 sieht man ja, dass \phi_t
stetig ist (obige Definition sieht ja fast schon so aus wie die
formale Definition der Stetigkeit, fehlen bloß noch ein paar
Quantoren und ein Epsiolon).

D.h. das man a(t) nicht direkt, sondern in 2 Schritten berechnet,
als erstes \phi_t aus \phi_{t - \Delta t} und dann a(t) = A *
sin(\phi + \theta)

Das funktioniert im Übrigen nicht nur mit sin/cos sondern mit
allen periodischen Funktionen.

Da man am Computer aber nur begrenzt viele Bits hat, sollte man
sicher stellen, dass man die Phase nach einem Umlauf modulo
zurücksetzt, sonst wird der Fehler zu groß. Entweder mit
Fließkomma und richtigem Modulo, oder man legt fest, dass ein
kompletter Umlauf in einer kompletten 2-erpotenz passiert und
lässt diesen Integer einfach überlaufen (dann kann man auch eine
Lookup-Tabelle verwenden, gerade bei komplexeren Funktionen ist
das nicht verkehrt, für sin/cos und anderen Einfachen aber
Platzverschwendung).

Wolfgang Draxinger
--
E-Mail address works, Jabber: ***@jabber.org, ICQ: 134682867
Christopher Creutzig
2007-10-02 13:57:21 UTC
Permalink
Post by Wolfgang Draxinger
betrachtet. Wenn nun \omega eigentlich \omega(t) ist und nicht
stetig bekommt man natürlich ein Problem, da die Verkettung
einer nicht stetigen mit einer stegigen wieder nicht stetig ist.
Da fehlt noch ein „im Allgemeinen“, denn natürlich kann die Verkettung
einer stetigen und einer unstetigen Funktion wieder stetig sein. Deine
Reduktion modulo 2*PI ist ja auch nicht stetig.
--
if all this stuff was simple, we'd
probably be doing something else. -- Daniel Lichtblau, s.m.symbolic
Loading...