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
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
//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.