Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Sound ausgabe 40 mal in der Sekunde (https://www.delphipraxis.net/46914-sound-ausgabe-40-mal-der-sekunde.html)

Six 2. Jun 2005 20:32


Sound ausgabe 40 mal in der Sekunde
 
Hallo :wink:

Da dies mein erster Beitrag in diesem super Forum ist (bisher habe ich immer nur mitgelesen :cyclops: ) möchte ich erstmal Hallo sagen :thumb: .

Hallo :hi:


So und nun zu meinem Problem:

Also, ich möchte ein Programm schreiben, das im wesentlichen Sounds ausgibt (auf meinen Befehl).
Bis hierhin nicht weiter schwierig, aber:

Der abgespielte Sound soll 40 mal in der Sekunde ab und angeschaltet werden können und das ist in der Tat nicht so einfach, da selbst präzisere Timer Probleme zu haben scheinen. Ich glaube aber, das dass Problem nicht an den Timern selber liegt, sondern vielmehr an der Verarbeitung des Sounds.
Damit meine ich, dass die Zeitspanne des Ladens und Stoppens des Sounds zu lange dauert.

Ich habs mit wav dateien probiert aber keinen Erfolg gehabt. Dann bin ich auf die Komponente ToneGen gestoßen, damit ging es etwas besser, aber zufriedenstellend war das auch nicht. Der Sound lässt sich schätzungsweise 15-20 mal zuverlässig in der Sekunde Triggern.

Das Programm soll am Ende den erzeugten Sound einfach als wav datei abspeichern. Ich möchte über eine bestimmte Zeitspanne die Hz Rate durch knopfdruck wechseln lassen. Das soll möglichst dynamisch sein. Die Rate möchte ich zum beispiel in 3 Sekunden um 10 Herz linear erhöhen oder von 30 auf 40 Herz setzten etc. . Das wird dann in Echtzeit aufgezeichnet. Der Sound an sich besteht dabei nur aus einer einfachen Sinuskurve, die sich eben zum Beispiel mit Tonegen erzeugen lässt.

Habt ihr Ideen, wie ich das mit dem an - aus Problem lösen könnte ?

Danke :-D

Six

Robert Marquardt 3. Jun 2005 07:04

Re: Sound ausgabe 40 mal in der Sekunde
 
Herzlich willkommen bei der Delphi-Praxis.
Ich glaube nicht das du auf diesem weg wirklich weiterkommst.
Wie waere es denn einen WAV Sound mit den Aenderungen vorzuberechnen und einfach abzuspielen?
Das sollte moeglich sein, allerdings sit das Soundverarbeitung von dem ich keine Ahnung habe.

FAlter 3. Jun 2005 07:35

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi,

Mit play-stop-play-stop wirst du wenig Erfolg haben. Entweder du berechnest den ganzen Sound vorab und gibst ihn da wieder (einfacher zu Coden) oder du berechnest den Anfang (ein paar Sekunden), startest die Wiedergabe und berechnest währenddessen den Rest.

Wenn du das Ergebnis dann berechnet hast, kannst du es dann auch als WAV speichern.

Mfg
FAlter

Six 3. Jun 2005 17:55

Re: Sound ausgabe 40 mal in der Sekunde
 
Erstmal danke für die Antworten :thumb:

Zitat:

Mit play-stop-play-stop wirst du wenig Erfolg haben. Entweder du berechnest den ganzen Sound vorab und gibst ihn da wieder (einfacher zu Coden) oder du berechnest den Anfang (ein paar Sekunden), startest die Wiedergabe und berechnest währenddessen den Rest.
Ja, genau so habe ich mir das eigentlich auch gedacht, aber da ich vorher nie mit sound gearbeitet habe, habe ich auch keinen Schimmer, wie ich das mit der Vorrausberechnung oder "Wärendessenberechnung" hinbekommen kann. Kannst du oder irgendjemand anderes mir da weiterhelfen?


Gruß

Six

Zacherl 3. Jun 2005 18:07

Re: Sound ausgabe 40 mal in der Sekunde
 
Mit Turbo Pascal kann man glab' ich über

Delphi-Quellcode:
Sound(Frequenz);
Delay(Dauer);
NoSound;
Sound aus dem integriertem Lautsprecher ausgeben.
Dann mit ner Schleife oder so arbeiten.

Wenns dir was bringt ... :wink:

Florian

Six 3. Jun 2005 18:30

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi Florian,

danke für den Tipp, aber leider bringt mir das nicht viel, da ich eine bestimmte Sinuskurve über die Standardlautsprecher ausgeben und vor allem auch aufzeichnen möchte.
Wahrscheinlich wäre auch diese Funktion zu langsam. Das Problem ist die Vorrausberechnung. Kennt da irgendjemand ein Tutorial zu oder ähnliches? Irgend etwas über fortgeschrittene Soundbearbeitung in Delphi... Audiacity ist ja leider in C++ verfasst und sich da einzuarbeiten ist für diesen Zweck leider auch ein bischen zu aufwendig... Aber wenn es sowas wie Audiacity in Delphi als open Source geben würde (kann ja auch viel einfacher sein), wäre mir schon sehr geholfen. Ich habe nur leider nichts in der Art gefunden.


Six

FAlter 4. Jun 2005 11:29

Re: Sound ausgabe 40 mal in der Sekunde
 
Tutorial kenn ich nicht, habs aber schonmal probiert. Ist eigentlich nicht schwer. Hier mal die Vorausberechnung eines Sinustones:

Delphi-Quellcode:
uses
  MMSystem;

var
  Format: TWaveFormatEx;
  Size:  Longint;
  Data:  PSmallInt; //für 8 Bit PByte verwenden


Um TWaveFormatEx mit gültigen Daten für ein PCM-Format (Pulse Code Modulation) zu füllen, habe ich mir das geschrieben (auch Bestandteil meiner Sound.dll)

Delphi-Quellcode:
{ Gültig sind: bei Bitrate = 8 ein oder zwei Channels,
bei 16 Bit ein, zwei oder vier Channels,
Sampleraten zwischen 100 Hz (nicht empfohlen!) und 10 kHz (= 10000 Hz)). Sampleraten in Hz angeben. }

function WavePCMFormat(const Channels, Bitrate: Word; const Samplerate: DWord): TWaveFormatEx;
begin
  with Result do
  begin
    nChannels := Channels;
    wFormatTag := WAVE_FORMAT_PCM;
    nSamplesPerSec := Samplerate;
    wBitsPerSample := Bitrate;
    nBlockAlign := nChannels * WBitsPerSample div 8;
    nAvgBytesPerSec := nSamplesPerSec * nBlockAlign;
    cbSize := 0;
  end;
end;
Dann setzt du Size auf einen bestimmten Wert:

Delphi-Quellcode:
Size := Round(Sekunden * nAvgBytesPerSec);
Wobei Sekunden irgendeine Zahl ist (z. B. Double). Wenn du nur mit ganzen Sekunden arbeitest (Integer), kannst du das Round weglassen.

Dann musst du den Speicher reservieren:

Delphi-Quellcode:
GetMem(Data, Size);
Um nun die Sinuskurve zu erstellen, brauchst du eine Zählschleife:

Delphi-Quellcode:
//für 8 Bit abwandeln!!
    X := Data; //X ist auch ain PSmallInt!
    for I := (Size div 2) - 1 downto 0 do
    begin
      X^ := Round(Sin(Y * Freq * Pi * 4 / Format.nAvgBytesPerSec) * 32767);
      inc(X);
    end;
Freq ist hierbei die gewünschte Frequent (z. B. 440 Hz fpr dier Note a'), es kann Douible oder Extended sein.

Zur Wiedergabe kannst du dann z. B. DirectSound verwenden. Da musst du meist Format oder @Format, Size und Data übergeben.

Für den Anfang ist DelphiX sehr einfacvh, wenn es auch veraltet ist und nicht mehr weiterentwickelt wird, aber bei DirectSound hat sich seitdem noch nicht viel geändert (im Gegensatz zu Direct3D).

SirThornberry 4. Jun 2005 11:33

Re: Sound ausgabe 40 mal in der Sekunde
 
also dein Vorhaben wird mit aller wahrscheinlichkeit scheitern. Professionelle Programme welche einen extra Treiber mitbringen der im Kernelbereich arbeitet oder Programme die im RealTimeModus arbeiten kommen in aller Regel bei der Latenz nicht unter 2 ms. Wenn du den DirectSound-Treiber von Windows verwendest so liegt die Latenz irgendwo um die 100 ms.

Six 4. Jun 2005 13:14

Re: Sound ausgabe 40 mal in der Sekunde
 
@ SirThornberry:

Ja, ich denke mittlerweile auch, dass es in Echtzeit scheitern wird, daher bin ich ja auch an der Möglichkeit interessiert, die Falter mir gerade versucht zu erklären.


@ Falter:

Danke für die Antwort. Ich muss nur leider zugeben, dass ich von dem ganzen Sound zeugs wie gesagt, leider keine Ahnung habe und hier im Moment nur Bahnhof verstehe :stupid:

Aber vielleicht steige ich da ja irgendwie durch.

Du schreibst, dass Sampleraten (ich nehme an, das ist die höhe des Tons) zwischen 100Hz und 10Khz möglich sind. Ich bräuchte aber um die 22Khz, ist das irgendwie zu bewerkstelligen (liegt nicht mehr im höhrbaren Bereich und soll auch nicht höhrbar sein)?
Was ist diese Sound Dll von der du sprichst, brauche ich die um den Code auszuführen? Brauche ich DelphiX um den Code auszuführen?

Kann man die Sinuskurve nicht irgendwie so berechnen, das einmal ein Ton hörbar ist und dann wider für eine bestimmte zeit nicht, dann kommt wieder ein Ton etc.? So wie auf den Herzfrequenzmessern im Krankenhaus?

Sorry, dass hört sich jetzt alles ziemlich dämlich an, aber es ist mein erstes Projekt in der Richtung und leider fehlen mir da auch einfachste Grundlagen. Wie hast du dir dein Wissen angeeigenet?

Gruß

Six

FAlter 6. Jun 2005 17:29

Re: Sound ausgabe 40 mal in der Sekunde
 
Zitat:

Zitat von Six
Du schreibst, dass Sampleraten (ich nehme an, das ist die höhe des Tons) zwischen 100Hz und 10Khz möglich sind. Ich bräuchte aber um die 22Khz, ist das irgendwie zu bewerkstelligen (liegt nicht mehr im höhrbaren Bereich und soll auch nicht höhrbar sein)?

Sorry, Null vergessen (100 kHz --> für 22,05 kHz setze Samplerate auf 22050 [Hz])

Zitat:

Was ist diese Sound Dll von der du sprichst, brauche ich die um den Code auszuführen? Brauche ich DelphiX um den Code auszuführen?
Die Sound.dll ist eine DLL. die ich selber entwickle. Du brauchst sie nicht. Ich habe Teile des Beispielcodes oben aus ihr Kopiert /(Copy&Paste&Anpass). Leider hat der Wiederrgabecode der Sound.dll momentan einen Bug. Beim verlassen der Proc wird (wenn es nicht der erste Aufruf ist) eine EAccesViolation ausgelöst. Tatsächlich in dieser Zeile:

Delphi-Quellcode:
procedure ...(...); stdcall;
var
  ...
begin
  ...
end; // <-- HIER
Ansonsteh hätte ich sie dir empfohlen... Aber erst muss die Exception weg, da sonst das gesamte Programm (das die DLL geladen hat), beendet wird :(

Zitat:

Kann man die Sinuskurve nicht irgendwie so berechnen, das einmal ein Ton hörbar ist und dann wider für eine bestimmte zeit nicht, dann kommt wieder ein Ton etc.? So wie auf den Herzfrequenzmessern im Krankenhaus?
Setze die nicht hörbaren Bereiche auf Null (z. B. 11025 Samples lassen, 11025 Samples Null, dann wieder unverändert, ...)

Vielleicht wäre es praktisch, wenn du verstehst, wie Audiodaten im PCM-Format aufgebaut sind...

Nehmen wir an, du hast zwei digitale Spannungsmesser an eine Audioquella engeschlossen und misst jetzt in jeder Seklunde 22050 mal die Spannung, ein Spannungsmessetr rechts und einen links.
Die Spannungsmesser bringen 16-Bit-Werte zwischen -3,2768 V* und 3,2768 V*. Du multiplizierst sie mit 10000 und speicherst sie nacheinander ab, erst links, dann rechts, dann den nächsten Messwert...

Damit hast du dein Geräusch als PCM-Rohdaten.

Zur Wiedergabe wird an den Soundkartenausgang mit den gleicghen Zeitabständen wie bei der Aufnahme die vorher gemessene und dann gespeicherte Spannung angelegt. Mit einem Leistungs-Verstärker in deiner aktiven Lautsprecherbox kannst du die Lautsprecher mit hohen Leistungen ansteuern und somit ganz laut Musik oder andere Klänge wiedergeben.

Jetzt fällt der Schritt der Aufnahme weg, du erzeugst selbst den Ton, mit Zuhilfenahme der Sinusfunktion.

PS: Ich kann hier für Richtigkeiten keine Gewähr geben. Ich habe das Prinzip, Töne in den Speicher zu schreiben, durch eigebnes Ausprobieren entdeckt, ohne irgendwo zu lesen. Bei mkir hat es zumindest funktioniert.

________
*) Es wird i. d. R. mit Spannungen unter 1 V gearbeitet (775 mV wäre Standard, wird aber meist nicht ganz eingehalten), das hier war nur zur einfacheren Veranschaulichung.

Six 8. Jun 2005 11:39

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi FAlter,

Danke für deine Hilfe :thumb:

Könntest du mir dafür vielleicht noch mal ein kleines Codebeispiel geben (möglichst Lauffähig):

Zitat:

Setze die nicht hörbaren Bereiche auf Null (z. B. 11025 Samples lassen, 11025 Samples Null, dann wieder unverändert, ...)
Wäre es damit möglich, die 40 An- und Ausschaltvorgänge zu ralisieren und wäre es dynamisch regelbar?

Besten Dank!

Six

FAlter 8. Jun 2005 12:30

Re: Sound ausgabe 40 mal in der Sekunde
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hier erstmal ein Beispiel MIT sound.dll, eventuell solltest du die nächste Zeit mal nachsehen, ob eine neue Version herausgekommen ist. Ein Beispiel ohne DLL werde ich eventuell nach dem Zelten nachliefern. (Das reimt sich ja!)

Ansonsten versuch es einfach mal selbst oder nehm zur Wiedergabe sowas einfaches wie DelphiX (denn es ist nur die Wiedergabe, die nicht ganz reibungslos funktioniert, also PlayPCMMemory).


So, ich fahr jetzt zelten!


:hello:
:hi: CU :hi:
:hello:

Six 21. Jun 2005 17:08

Re: Sound ausgabe 40 mal in der Sekunde
 
Sorry, dass ich mich so lange nicht gemeldet hatte, aber ich hatte in letzter Zeit keinen Internet Zugang.

@ Falter: Danke für die Hilfe und deine Dateien! Ich hoffe ich komme in nächster Zeit mal dazu das ganze auszuprobieren.

Ich würde mich gerne noch weiter in das Thema einarbeiten, habe aber wie gesagt, keine kostenlosen tutorials etc. gefunden.

Hat sich denn außer Falter noch niemand mit dem Thema Soundbearbeitung und Delphi auseinandergesetzt? :gruebel:


Six

Six 21. Jun 2005 21:02

Re: Sound ausgabe 40 mal in der Sekunde
 
Soooo, also ich habe jetzt ein wenig mit deinem Beispiel (Danke, Danke Danke :mrgreen: ) herumprobiert und stellte fest, dass damit eine 40 Hz Frequenz wirklich kein Problem ist :thumb:

Den Ton an sich soll man übrigens nicht hören können, da er nur als Signal dient.
Jetzt habe ich allerdings ein Problem. Ich habe zunächst Sinus auf Square gesetzt nur höre ich jetzt bei jedem Ein- und Ausschaltvorgang ein Knacken (auch bei Sine). Es ist ganz wichtig für mich, die Steuerung komplett lautlos zu machen, wie bekomme ich also dieses Knacksen weg?

Und: Wie kann ich den linken und rechten Kanal getrennt steuern?

Zum beispiel möchte ich den rechten Kanal 10 mal in der Sekunde und den linken Kanal 20 mal in der Sekunde Ein- und Ausschalten lassen. Ist das irgendwie möglich?


Danke für eure Hilfe!

Six

FAlter 22. Jun 2005 14:08

Re: Sound ausgabe 40 mal in der Sekunde
 
Wenn TWaveFormatEx.Channels auf 2 steht, wechseln sich immer linker und rechter Channel ab, also bei 22050 Hz hast du 44100 Smallint-Werte in einer Sekunde Daten. Der erste ist links, Sample 1, der zweite ist rechts, Sample1, dann links Sample 2...

Überleg dir selbst was oder mach zwei Mono-Sounds wie zuvor dargestellt und mische sie dann zusammen (doppelt so viel Speicer wählen und dann abwechselnd Werte von einem und anderen Stream nehmen, in Zählschleife etwa

Delphi-Quellcode:
//Size = Größe der Quellsounds (beide gleich)
//ziel, quelle1, quelle2 wieder PSmallInt

GetMem(ziel, 2*size);

for i := (Size div 2) - 1 downto 0 do //div 2 wegen 16 Bit = 2 Bytes
begin
  ziel^ := quelle1^;
  inc(Ziel);
  ziel^ := quelle2^;
  inc(Ziel); // <-- edit: ergänzt, fehlte
end;
//edit: Siehe Quellcode :oops: ich glaube ich sollte mit 'nen Shortcut für den :oops: anlegen :D

Six 22. Jun 2005 17:20

Re: Sound ausgabe 40 mal in der Sekunde
 
Ok, danke, werde ich probieren.

Aber hast du auch eine Idee, wie ich das knacksen vermeiden kann? Wenn ich das nicht wegbekomme, ist die ganze Sache leider unbrauchbar :pale:

mfg Six

FAlter 22. Jun 2005 18:09

Re: Sound ausgabe 40 mal in der Sekunde
 
Naja, bei meinem Beispiel hör ich kein Kancksen...

Aber vermutlich hast du zufälligerweise eine Unterbrechung an einer Stelle der Sinuskurve, an der keine Nullstelle ist (beim Rechtecksignal gibt es keine Nullstellen, sondern einen direkten Wechsel des Vorzeichens, aber das Problem sollte das gleiche sein: Unterbrechung des Sounds an falscher Stelle).

Du könntest die Zeit der Unterbrechung unwesentlich ändern, so, dass der User es nicht merkt, aber die Zeitpunkte der Nullstellen der Funktion (bzw. bei Rechteck die Zeitpunkte des Wechsels zwischen den Vorzeichen, sind dieselben Zeitpunkte wie die Nullstellen bei Sinus) den Zeitpunkten beim ein- bzw. ausschalten des Tones entsprechen. Bei einer "normalen" Sinusfunktion kommen die Nullstellen bei allen ganzzahligen Vielfachen von Pi.

Dank unserer netten Sinusfunktion

Delphi-Quellcode:
Sin(Y * Freq * Pi * 4 / Format.nAvgBytesPerSec)
ist das hier ein wenig abgewandelt. Jede halbe Schwingungsdauer kommt eine Nullstelle, wobei eine Schwingungsdauer der Kehrwert der Frequenz ist. Bei einer Frequenz von 1 Hz ist die Schwingungsdauer 1 Sekunde, das heißt, der Nullpunkt wird alle 0,5 s durchlaufen.

Sorge also dafür, dass deine An/Aus-Vorgänge an (1 / Frequenz / 2) ausgerichtet werden. (Voraussetzung: Die An-Aus-Frequenz ist kleiner als die Tonfrequenz).

Eine andere Alternative sind Fade-in und Fade-out über nur sehr wenige Samples.

Ein Fade-in bzw. Fade-out ist das lauter- bzw. leiserwerden des Tones.

So könntest du z. B. dein gesamtes Werk lauter werden lassen:

Delphi-Quellcode:
procedure FadeInPCM16Bit(Data: PSmallInt; Size: Integer);
var
  I: Integer;
  DataLength: Integer;
begin
  DataLength := Size div 2;

  for I := 1 to DataLength do
  begin
    Data^ := Data^ * I div DataLength;
    inc(Data);
  end;
end;
Das ganze musst du so abwandeln, dass es nur einige wenige Samples entspricht, eventuell eine halbe oder eine viertel Schwingungsdauer der Tonfrequenz, und dass es an jedem Einschaltvorgang kommt.

Analog lassen sich Ausschaltvorgänge mit Fade-out realisieren... Da musst du nur die Richtung der Zählschleife umkehren... Diese dann für die Ausschaltvorgänge abwandeln...

Delphi-Quellcode:
procedure FadeInPCM16Bit(Data: PSmallInt; Size: Integer);
var
  I: Integer;
  DataLength: Integer;
begin
  DataLength := Size div 2;

  for I := DataLength - 1 downto 0 do //downto 0 ist schneller als downto 1 und der
                                      //Unterschied ist für Menschen nicht hörbar ;)
  begin
    Data^ := Data^ * I div DataLength;
    inc(Data);
  end;
end;
PS: Sources nicht getestet ;) gilt auch für vorigen Post.
//edit: uns schon die ersten Fehler gefunden :oops:
//edit2: Hab mal den Fadein-Code getestet.. hört sich scheißlich an, irgendwo kommt es da zu einem Überlauf? Data^ * I dürfte das Problem sein, delphi Rechnet das zwar intern mit 32 Bit aus und dividiert danach, aber wenn I zu groß ist... Meinetwegen rechne mit Int64-Werten, und wenn das nicht funktioniert... rechne mit Extended-Werten und verwende dann Round.

Six 22. Jun 2005 18:34

Re: Sound ausgabe 40 mal in der Sekunde
 
Danke Falter!

Ich hoffe, ich kann das auch mit dem Rechtecksignal verwenden. Da meine Frequenz bei 22000Hz liegt, sollten eigentlich genügend Nullstellen vorhanden sein. Das Rechtecksignal eignet sich für meine Zwecke deutlich besser.

Ich habe deinen Code ein wenig abgeändert, da er bei höheren Frequenzen nicht mehr funktioniert hat:

Delphi-Quellcode:
    for I := 1 to (Size div Format.nChannels) do
    begin
      if
        I mod 4450 = 0
        then
        Aus := not Aus;

      if Aus then
        Data2^ := 0;

      inc(Data2);
    end;
Das entpricht etwa 10 Ein- und Ausschaltzyklen in der Sekunde.

Würde das alles eigentlich auch mit der Bass.dll funktionieren oder wäre das ganze auch ganz ohne Dll möglich? Ich frage, weil mir durch die Dll viele Dinge verborgen bleiben, die ich eigentlich wissen müsste, um das ganze etwas besser zu verstehen... Wie hast du dir dein ganzes Wissen in diesem Bereich angeeignet?

Ich probiere dann mal die Sache mit dem Knacksen zu beseitigen. Wenn ich keinen Erfolg habe, frage ich nochmal.

Wie kann ich zwei Sounds zusammenmischen, also beispielsweise einen 500 Hz und einen 800 Hz Ton, oder zwei wav Dateien?

Abermals vielen Dank!

Six

FAlter 22. Jun 2005 18:44

Re: Sound ausgabe 40 mal in der Sekunde
 
Du kannst auch die Bass.dll verwenden, aber mit der kenn ich mich nicht so aus, aber du siehst ja, dass das ganze hauptsächlich auf Arbeit mit Pointern hinausläuft, und jede gute Audio-DLL unterstützt es, durch Angabe eines Formats, der Größe der Rohdaten und dem Pointer auf die Rohdaten den Sound wiederzugeben.

[ot]
Was mich wundert ist, dass du bei 22000 Hz = 22 kHz noch etwas hörst, ab 16 kHz können Menschen einen Ton nämlich gewöhnlcih nciht mehr wahrnehmen. Bist du ein Außerirdischer? Oder eine Mutation? Oder hast du Katzengene? (Unsere Katzen können diese Töne sicher hören, frag mal eine davon...)

Oder meintest du die Samplerate? Ich meinte im obigen Post die Frequenz des Tones selbst. Für 16 kHz benötigst du zur Speicherung mindestens 32 kHz Samplerate, aber da gehen noch sehr viele Infos verloren. Deshalb höret sich 8 kHz-Musik so schreklich an, weil alles jenseits von 4 kHz wegfällt und ein großer Teil verzerrt ist.
Wenn du mit einer niedrigen Tonfrequenz arbeitest (unter 1 kHz), dann sollten deine 22 kHz Samplerate genügen, und mit 40-Hz-Unterbrechungen sollte es auch keine Probleme mehr geben.

[/ot]

FAlter 22. Jun 2005 18:48

Re: Sound ausgabe 40 mal in der Sekunde
 
Zitat:

Zitat von Six
Wie kann ich zwei Sounds zusammenmischen, also beispielsweise einen 500 Hz und einen 800 Hz Ton, oder zwei wav Dateien?

:oops: Übersehen...

Addiere die Samples der Sounds, wenn sie sehr laut sind, dann bilde den Durchschnitt...

Delphi-Quellcode:
//Size = Größe der Quellsounds (beide gleich)
//ziel, quelle1, quelle2 wieder PSmallInt

GetMem(ziel, 2);

for i := (Size div 2) - 1 downto 0 do //div 2 wegen 16 Bit = 2 Bytes
begin
  ziel^ := (quelle1^ + quelle2^) div 2;
  inc(Ziel);
end;
Bei unterschuiedlich langen Sounds fülle den kürzeren am Ende mit Nullsamples...

//edit: Hatte versehentlich quote- statt delphi-Tags genommen :oopa: <-- der neue Standardsmiley

Six 22. Jun 2005 18:53

Re: Sound ausgabe 40 mal in der Sekunde
 
Nein, ich bin KEIN Mutant :wink:

und du hast schon recht, wenn wir hier durcheinanderkommen, da ich in zwei verschiedenen Zusammenhängen von Frequenz spreche. Also nochmal zur Verdeutlichung: Der eigentliche Ton hat eine Frequenz von 22000Hz. Den kann und soll natürlich kein Mensch mehr hören, da er als Signal dient, um etwas anderes zu Steuern. Mit 40 Hz beispielsweise meine ich dann die Frequenz, mit der dieser 22000Hz Ton an- und ausgeschaltet wird. Die Samplerate (?) liegt bei 44100 Hz, sonst hört sich der 22000Hz Ton ja nicht an wie er soll, bzw. wird hörbar.

In meiner Anwendung, will ich nun diese An- und Ausschaltvorgänge vom Benutzer vorgeben und anschließend abmischen lassen. Dabei rauskommen soll dann eine Datei, mit einem gleichbleibenden Ton von 22000 Hz, der mit unterschiedlichen Frequenzen unterbrochen wird.

So, ich hoffe ich habe alle Klarheiten beseitigt :thumb:


Six

Six 24. Jun 2005 11:42

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi Falter,

Also so wie's aussieht komme ich jetzt klar und deshalb markiere ich den Post jetzt erstmal als gelöst. Nochmals vielen Dank, du hast mir die Augen geöffnet :spin:

Falls du Lust hast, könntest du ja mal ein Grundlagen Tutorial über die ganze Sache schreiben, leider ist da noch nicht viel in der Richtung verfügbar (eigentlich gar nichts?).

Eine Sache gibts aber dennoch, die ich noch nicht verstanden habe:

Delphi-Quellcode:
  DataLength := Size div 2;

  for I := 1 to DataLength do
Warum muss hier die DataLength durch zwei geteilt werden? Entspricht das einem Fade In über die ganze Länge des Sounds?

Hast du eigentlich vor den Source deiner Sound.dll zu veröffentlichen?


Six

FAlter 24. Jun 2005 17:00

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi,

Size entspricht der Größe in Bytes (!), die deine Sounddaten haben. Wenn du mit 16-Bit-Sounds arbeitest, ist eine Teilinformation zwei Bytes groß, das heißt die Gesamtzahl aller Teilinformationen ist die Hälfte der Anzahl der Bytes, da eine Teilinformation doppelt so groß ist (16 statt 8 Bits --> 2 statt 1 Byte).

Als Teilinformation verstehe ich hierbei einen Kanal innerhalb eines Samples.

Den Source gibts vorerst nicht.

Mfg
FAlter

Six 26. Jun 2005 18:10

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi Falter,

Sorry, aber ich brauche noch einmal deine Hilfe...

Ich möchte zwei gleich lange Monosounds zu einem Stereosound zusammenmischen. Dabei sollen die Monospuren jeweils dem Linken und rechten Soundkanal der erzeugten Stereodatei entsprechen. Dafür habe ich deinen Code folgendermaßen eingebaut:

Delphi-Quellcode:
Quelle1:=Data; // erster Monosound
Quelle2:=Data3; //zweiter Monosound
GetMem(ziel, 2*size);
for i := (Size div 2) - 2 downto 0 do //div 2 wegen 16 Bit = 2 Bytes
begin
ziel^ := quelle1^;
inc(Ziel);
ziel^ := quelle2^;
inc(Ziel); // <-- edit: ergänzt, fehlte
end;
SavePCMMemoryToFile(Ziel, 'C:\Result.wav', Format, Size); //Abspeichern
Leider bekomme ich bei der Verwendung dieses Codes eine nichtssagende Fehlermeldung und ich glaube auch nicht, dass ich damit zwei Monospuren zu einer Stereodatei zusammenfügen kann, richtig? Ich denke du dachtest, ich wollte zwei Mono- oder Stereosounds mischen. Wie kann ich also zwei Monosounds zu einem Stereosound zusammenmischen?

Und noch eine andere Sache ist mir aufgefallen, die ich nicht verstehe: diese Data2:=Data Geschichte... Was ist der Zweck des ganzen, warum kann man nicht einfach direkt mit Data arbeiten? Und dann wird nur noch mit data2 gearbeitet und am ende steht das Ergebnis dann doch wieder in data?! Habe ich da irgendwo eine zweite Zuweisung am Ende übersehen, oder wie geht das (Ich hoffe du verstehst, was ich meine :wink: ).

Dankeschön :thumb:

Six

FAlter 26. Jun 2005 18:30

Re: Sound ausgabe 40 mal in der Sekunde
 
Liste der Anhänge anzeigen (Anzahl: 1)
Hi,

Zitat:

Zitat von Six
Leider bekomme ich bei der Verwendung dieses Codes eine nichtssagende Fehlermeldung und ich glaube auch nicht, dass ich damit zwei Monospuren zu einer Stereodatei zusammenfügen kann, richtig? Ich denke du dachtest, ich wollte zwei Mono- oder Stereosounds mischen. Wie kann ich also zwei Monosounds zu einem Stereosound zusammenmischen?

Nein, eigentlich habe ich dich richtig verstanden, aber wie gesagt, das war ein ungetesteter, schnell ohne Delphi-IDE dahergetippter Beispielcode...

Wie genau geht denn die nichtssagende Fehlermeldung, evtl. Exception-Klasse, wo tritt er auf?

Zitat:

Und noch eine andere Sache ist mir aufgefallen, die ich nicht verstehe: diese Data2:=Data Geschichte... Was ist der Zweck des ganzen, warum kann man nicht einfach direkt mit Data arbeiten? Und dann wird nur noch mit data2 gearbeitet und am ende steht das Ergebnis dann doch wieder in data?! Habe ich da irgendwo eine zweite Zuweisung am Ende übersehen, oder wie geht das (Ich hoffe du verstehst, was ich meine :wink: ).
Der Zweck ist folgender:

Zitat:

Zitat von RAM
Addr: Word
Addr+2: Word

Nehmen wir an, dein Pointer Data hat den Inhalt Addr. Bei der Verarbeitung weist du dem signed Word (in Delphi: Smallint) an dieser Stelle einen Wert zu (Data^ := xyz;) und setzt den Pointer an die nächste Stelle (inc(Data)), zwei Bytes weiter (Addr+2). Das ganze passiert sehr oft.

Nach der Verarbeitung benötigst du zur weiteren Verarbeitung oder zur Wiedergabe wieder den Anfangswert. Entweder du stellst den Wert durch Rechnugng wieder her (dec(Data, AnzahlDerElementeDieDerZeigerZurueckgesetztWerdenS oll)) oder du änderst ihn gar nicht, sondern nutzt zwischendurch einen "Hilfszeiger".

Das besondere ist eben die Arbeit mit Zeigern. Ein Zeiger speichert eine Adresse im RAM, er zeigt sozusagen auf diese Speicheradresse. Wenn du zwei Zeiger hast, die auf die gleiche Adresse zeigen, und den Wert, auf dem einer der beiden Zeiger zeigt, änderst, ändert sich der Wert an dieser Speicheradresse und somit auch der Wert an der Adresse, auf die der andere Zeiger zeigt.

Eine gute Einführung zu Zeigern gibt es hier:
http://www.dsdt.info/grundlagen/sprache/zeiger.php

Mfg
FAlter

PS: Ich habe 'ne neue Version der SOUND.dll herausgebracht. Ein großer Teil der AVs trewten jetzt nicht mehr aus.

//edit: Oh mann, es gibt ja wirklich 'nen User "RAM". Ich meine hier den Random Access Memory.

Six 26. Jun 2005 18:38

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi,

Zitat:

Wie genau geht denn die nichtssagende Fehlermeldung, evtl. Exception-Klasse, wo tritt er auf?
So wie ich das gesehen habe tritt er an der Stelle des Speicherns auf und die erzeugte Datei hat erstens nur eine Spur und ist zweitens leer :gruebel:

Wo wird denn mitgeteilt, wie die erzeugte datei Aussehen soll und das sie zwei Spuren hat?

Bist du dir sicher, dass es wirklich mit dem Code funktionieren sollte?


PS: Danke für den Link und die Datei!

Six

FAlter 26. Jun 2005 18:41

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi,

Sieht so aus, als ob du das WaveFormat vom MONO-Sound genommen hast. Bei Stereo musst du ein neues WaveFormat nehmen. Du solltest dieselben Daten nehmen bei meiner Funktion zum PCM-Wave-Format-Erstellen, außer, dass bei Channels nicht 1 sondern 2 steht.

Mfg
FAlter

Six 26. Jun 2005 18:46

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi,

Also muss ich "Ziel" irgendwie erst als Stereosound deklarieren? Aber wie?

Delphi-Quellcode:
  FormatStereo := PCMWaveFormat(2 {Stereo}, 16 {Bits}, 44100 {Hz Samplerate});
  Ziel := CreatePCMRectMemory(22000, 1000, @FormatStereo, @Size);
So gehts ja nicht, weil ich ja keine Sounddatei erzeugen möchte... was meinst du also?

Six

FAlter 26. Jun 2005 18:50

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi,

Dein Code:

Zitat:

Zitat von Six
Delphi-Quellcode:
Quelle1:=Data; // erster Monosound
Quelle2:=Data3; //zweiter Monosound
GetMem(ziel, 2*size);
for i := (Size div 2) - 2 downto 0 do //div 2 wegen 16 Bit = 2 Bytes
begin
ziel^ := quelle1^;
inc(Ziel);
ziel^ := quelle2^;
inc(Ziel); // <-- edit: ergänzt, fehlte
end;
SavePCMMemoryToFile(Ziel, 'C:\Result.wav', Format, Size); //Abspeichern

Änderung:

Delphi-Quellcode:
Quelle1:=Data; // erster Monosound
Quelle2:=Data3; //zweiter Monosound
GetMem(ziel, 2*size);
for i := (Size div 2) - 2 downto 0 do //div 2 wegen 16 Bit = 2 Bytes
begin
ziel^ := quelle1^;
inc(Ziel);
ziel^ := quelle2^;
inc(Ziel); // <-- edit: ergänzt, fehlte
end;

//Änderung
FormatStereo := PCMWaveFormat(2 {Stereo}, 16 {Bits}, 44100 {Hz Samplerate});
//Änderung ende


SavePCMMemoryToFile(Ziel, 'C:\Result.wav', {Änderung}FormatStereo{Änderung Ende}, Size); //Abspeichern
Also nur ein anderes WaveFormat nehmen, den Stereosound hast du ja bereits als ein solcher erstellt.

Mfg
FAlter

Six 26. Jun 2005 18:56

Re: Sound ausgabe 40 mal in der Sekunde
 
Ohhhh, ja, wie dumm von mir :wall: :wall: :wall:

Danke vielmals Falter :thumb:

Six

Six 26. Jun 2005 19:41

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi Falter,

Es funktioniert leider immer noch nicht. Die Exception, die ich bekomme ist übrigens eine Zugriffsverletzung. Ich bin hier langsam echt am verzweifeln :?

Wo liegt der Fehler?


Six

FAlter 27. Jun 2005 14:33

Re: Sound ausgabe 40 mal in der Sekunde
 
So genau hatte ich mir deinen Code gar niocht angesehen, du hattest noch einen Fehler drin:

Delphi-Quellcode:
GetMem(Ziel, ...)

for...
begin
  ...
  inc(Ziel);
end;

SavePCMMemoryToFile(Ziel, ...);
Du musst den Pointer auf den Anfang deiner Daten übergeben, du übergibst aber einen Pointer auf das Ende!

FALSCH:
Delphi-Quellcode:
GetMem(Data);
inc(Data);
SavePCMMemoryToFile(Data);
RICHTIG:
Delphi-Quellcode:
GetMem(Data);
Data2 := Data;
inc(Data2);
SavePCMMemoryToFile(Data);
Also genau das, wo du gestern gefragt hast, warum man es machen muss, hast du vergessen.

Six 27. Jun 2005 15:00

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi Falter,

ich habe diese Möglichkeit auch breits ausprobiert, nur was dabei rumkommt, ist zwar eine Stereodatei, die jedoch nur halb so lang ist wie das Ausgangsmaterial und einen "verkrüppelten" Inhalt hat.

Also mein Code sieht dann mittlerweile so aus:

Delphi-Quellcode:
GetMem(Ziel, Size*2);
Ziel2:=Ziel;
for i := (Size div 2) -1 downto 0 do // Warum wird hier eigentlich nach unten gezählt?
begin
ziel^ := Data^;
inc(Ziel2);
ziel^ := Data3^;
inc(Ziel2);
end;
SavePCMMemoryToFile(Ziel, 'C:\Result.wav', FormatStereo, Size);
Was um alles in der Welt läuft hier bloß schief :gruebel:


Six

FAlter 27. Jun 2005 15:07

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi,

Du solltest deinen Code vor dem Posten nochmal genau ansehen. Dann findest du solche Fehler bestimmt selbst.

Delphi-Quellcode:
ziel2^ := Data^;
inc(Ziel2);
ziel2^ := Data3^;
inc(Ziel2);
Zum nach unten Zählen: Wenn du die Codeoptimierung an hast, würde der Compiler eh den Code für nach unten zählen generieren, weil es schneller ist, mit null zu Vergleichen, als mit was-auch-immer-bei-der-Berechnung-rauskommt.
In diesem Fall ist die Zählrichtung egal.

Mfg
FAlter

Six 27. Jun 2005 23:03

Re: Sound ausgabe 40 mal in der Sekunde
 
Hi Falter,

Stimmt, hatte ich übersehen :oops:

Leider ist die erzeugte Datei einfach Leer (die anderen beiden Dateien werden richtig erstellt!)

Mit "Leer" meine ich, es wird eine Stereodatei erstellt, die die richtige Länge hat (Size*2), jedoch keine Informationen enthält.

Delphi-Quellcode:
GetMem(Ziel, Size*2);
Ziel2:=Ziel;
for i := (Size div 2) -1 downto 0 do
begin
ziel2^ := Data^;
inc(Ziel2);
ziel2^ := Data3^;
inc(Ziel2);
end;
SavePCMMemoryToFile(Ziel, 'C:\Result.wav', FormatStereo, Size*2); // *2 hinzugefügt
SavePCMMemoryToFile(Data, 'C:\Test2.wav', Format, Size);          // Datei Mit Signal
SavePCMMemoryToFile(Data3, 'C:\Test3.wav', Format, Size);         // Datei mit SinusTon
Hmmm, woran könnte es denn noch liegen :gruebel:

Six

Six 29. Jun 2005 00:20

Re: Sound ausgabe 40 mal in der Sekunde
 
Hier die entscheidende Stelle, für jeden, der es eventuell noch brauchen kann:

Delphi-Quellcode:
      GetMem(Ziel, Size * 2);
        Ziel2 := Ziel;
        Data2 := Data;
        Data4 := Data3;

        for i := (Size div 2) - 1 downto 0 do
        begin
          ziel2^ := Data2^;
          Inc(Ziel2);
          inc(Data2);
          ziel2^ := Data4^;
          Inc(Ziel2);
          inc(Data4);
        end;
Nochmals vielen Dank an Falter!

Six


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:41 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz