Sinus-Ton-Generator

Unicate

Erfahrenes Mitglied
Hallo alle zusammen!


Ich möchte mir einen Sinuston bauen. Die Länge der PCM Information (Länge des Wellenabschnitts) und Frequenz (Höhe des Tons) sollte dabei variabel sein.

Das ganze sollte Stereo in 44,1kHz rauskommen.

Jetzt soll das noch geloopt werden, sodass wenn ich 1/10tel Sekunde PCM Daten erzeugt habe, diese dann wiederholt wird, sodass ich einen ewig langen Sinuston habe.

Problem auf das ich hier gestoßen bin, ist die Berechnung des Sinus.
Hier den Code den ich für die Berechnung verwende:
C++:
// create sinus chunk
	// sample rate
	_sampleRate = 44100;
	// PCM format 0x01
	_dataFormat = 0x01;
	// stereo
	_channelCount = 2;
	// bits per sample
	_bitsPerSample = 16;
	// framesize = (bytes/sample) * channel count
	_frameSize = _channelCount * (_bitsPerSample/8);
	// => 441000 * 4 = 176400 bytes/sec
	_bytesPerSecond = _sampleRate * _frameSize;
	// 1/10th of a second
	int samples = _bytesPerSecond/10;
	if(!_data)
		_data = new int16_t[samples];

	_dataLenght = samples;

		const double pi = 4*atan(1.f);
	for(int i=0;i<samples;i+=_channelCount) {
		double s = (i/_sampleRate) * (2*pi*value);
		for(int j=0;j<_channelCount;j++) {
			_data[i+j] = sin(s) * 10000;
		}
	}
	return true;

Problem ist, das bei 17640 Schleifenaufrufen und einen gerundeten 2*PI die Sinuskurve nicht genau bei 0 endet, was zu einem Knacksen beim loop führt.

Meine Fragen:
Hat irgendjemand einwände was die Berechnung der Samples angeht? Ich bin neu auf diesem Gebiet und somit noch etwas frisch in der Tonberechnung :| .

Wie kann ich den Sinus an der Stelle so berechnen, das ich bei 17640 Samples am Ende auf meine 0 komme?
 
Zuletzt bearbeitet:

Bratkartoffel

gebratene Kartoffel
Premium-User
Hi,

bin mir zwar nicht sicher, aber du könntest zwei Änderungen mal probieren:

1. Erhöhe die Genauigkeit von deinem 2*PI (6.283185307179586476925286766559)
2. Setze deinen letzten oder die letzten beiden Frames manuell auf 0 nach der Berechnung

Grüße,
BK
 

Unicate

Erfahrenes Mitglied
Gute Idee mit dem "am Ende auf 0 setzen", aber funktioniert hat es trotzdem nicht.

Egal was ich mache, ich komm auf folgenden Effekt:

Wenn ich den Sound das erste mal starte kommt er sauber, egal welche Frequenz ich einstelle.
Sobald ich die Frequenz "während der Laufzeit" ändere kommt stocken rein.

Ich verwende OpenSLES mit 2 Buffern. Einen der gerade ausgegeben wird und der andere bekommt die neue Frequenz eingestellt.
 

Unicate

Erfahrenes Mitglied
Problem war ein Rundungsfehler in der Frequenz

Wenn man die letzte Stelle der Frequenz abrundet, kommt der Ton sauber.

Aus 1111Hz wird z.B. 1110Hz.


Hier nochmal der Code dafür. Er ist noch nicht ganz richtig. Wenn ich zum beispiel von stereo auf Mono schalte, dann wird der Ton noch tiefer, aber das find ich noch raus ;)

C++:
bool SinusSample::update(uint16_t value, float secondMultiplier) {

	value = (value/10)*10;
	if(_currentFrequence != 0 && _currentFrequence == value) {
		return true;
	}
	_currentFrequence = value;
	// create sinus chunk
	// sample rate
	_sampleRate = 44100;
	// PCM format 0x01
	_dataFormat = 0x01;
	// stereo
	_channelCount = 2;
	// bits per sample
	_bitsPerSample = 16;

	// framesize = (bytes/sample) * channel count
	_frameSize = _channelCount * (_bitsPerSample/8);
	// => 441000 * 4 = 176400 bytes/sec
	_bytesPerSecond = _sampleRate * _frameSize * _channelCount;
	//
	int samples = _sampleRate * secondMultiplier;
	if(!_data) {
		_data = new int16_t[samples];
	}

	_dataLenght = samples * (_bitsPerSample/8);
	for(int i=0;i<samples;i+=_channelCount) {
		double s = ((double)i/(double)_sampleRate) * (6.283185307179586476925286766559*value);
		for(int j=0;j<_channelCount;j++) {
			_data[i+j] = sin(s) * 10000;
		}
	}
	return true;
}


[Edit:]
Mono/Stereo Problem gelößt ;)
 
Zuletzt bearbeitet: