Archiv verlassen und diese Seite im Standarddesign anzeigen : Encoding PCM to g711 uLaw
Hi an alle,
ich nehme über die Windows Media Library sounddaten auf und zqwar im PCM Format, da wenn ich das MuLaw Format nutze die Message MM_WIM_DATA nicht mehr abgefangen wird. Mein Problem nun ist, das die Methoden die ich finden konnte zum encodieren der aufgenommenen Daten einen Integer erwarten. Beim Auslesen der Daten aus WAVEHDR sind die Daten aber in einem LPSTR geschrieben. Wie kann ich denn dieses ins G711 uLaw Format nun encodieren?
Gruß
Karsten
Kennt sich keiner aus mit der G711 Encodierung?
Kennt sich keiner aus mit der G711 Encodierung?
Im Bereich der Telekommunikationstechnik gibt es zwei gebräuchliche Kodierungen, die lediglich eine Transkodierung und keine Komprimierung und/oder Paketisierung des Signalstroms anbieten. Beide stammen aus dem ISDN- und PDH-Umfeld, stammen also originär aus dem Zeitraum der späten 70er/frühen 80er.
Die beiden Kodierungen sind das a-Law und das µ-Law, beide sind ITU standardisiert. Sowohl das a-Law, als auch µ-Law verwenden eine grob logarithmische Quantisierungskennlinie, die in verschiedene Segmente aufgeteilt ist. Die Quantisierungsraum umfasst 8 Bit, d.h. es werden 255 diskrete Werte abgebildet. Durch die logarithmische Kennlinie entspricht der Dynamikumfang jedoch einer 12-Bit-Quantisierung.
µ- und a-Law unterscheiden sich nur marginal in der Kennlinie und Kodierungswerten, sind aber sowohl technologisch, von der Kodierungsqualität, Stabilität, SNR und bei diversen statistischen Parametern gleichwertig. Eine Transkodierung von a- zu µ-Law (und umgekehrt) ist (fast) transparent und führt zu (fast) identischen Werten.
Das a-Law wird bei ISDN in Europa und fast der gesamten Welt verwendet, das gleichwertige µ-Law dagegen in Nordamerika und Japan. Für VoIP ist G.711 ein zugelassener und als "mandatory" geführter Codec mit guter Verständlichkeit zu Lasten der Bandbreite (G.711 enkodiert einen Frequenzbereich von 300 bis 3400 Hz mit einem 14-Bit-Sample alle 125µs, der zu einem 8 Bit-PCM-Datenstrom kodiert wird (8kHz * 8 Bit = 64000 bit/s == ISDN-B-Kanal)).
Eine Kodierungsübersicht und Beschreibung findest du hier: http://www.itu.int/rec/T-REC-G.711-198811-I/E
Zu deinem eigentlichen Problem... Die einfachste Lösung wäre, eine LUT zu verwenden, da a- wie µ-Law statisch und kontextfrei sind: Es handelt sich nur um eine simple Kodierung.
Da der Dynamikumfang einem 12-Bit-Sample entspricht, reicht auch maximal eine 12-Bit-LUT, als 4096 Einträge. Bei 16-Bit-Samples kannst du also die 4 LSB einfach wegwerfen (rausrotieren, SHR). Bei 8-Bit Samples reicht eine 8-Bit-LUT mit 256 Werten. Eines noch: a- und µ-Law sind nicht stereotauglich. Es wird immer nur ein Monokanal kodiert. Eventuelle Stereodaten müsstest du also vorher in Mono wandeln.
Oy da muss ich mich doch mal ein bißchen genauer mit auseinander setzen aber danke für den Anstoss.
So habe mich nun noch einmal ein wenig intensiver mit der codierung auseinander gesetzt.
Ich versuche im Moment einen muLaw Stream in 8Bit lineares PCM mit 8000hz zu decodieren bekomme aber nur ein Rauschen ausgegeben.
Hier mein Code.
for(int i = 0; i < uSize; i++)
{
if(pG711->decodeULaw(szBuffer[i]) > 0)
{
p[iBuf] = pG711->decodeULaw(szBuffer[i]);
iBuf++;
}
}
lpWaveHdr->dwBufferLength = uSize;
lpWaveHdr->lpData = p;
m_mmr = waveOutPrepareHeader(m_hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
if(m_mmr)
{
waveOutGetErrorTextA(m_mmr, szErr, sizeof(szErr));
returnfalse;
}
m_mmr = waveOutWrite(m_hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
if(m_mmr)
{
waveOutGetErrorTextA(m_mmr, szErr, sizeof(szErr));
returnfalse;
}
//Sleep(500);
if(waveOutUnprepareHeader(m_hWaveOut, lpWaveHdr, sizeof(WAVEHDR))== WAVERR_STILLPLAYING)
{
Sleep(100);
}
//Hier die Methoden aus der G711 Klasse
//Table
const short ulaw2linear_tab[256] =
{
-32124,-31100,-30076,-29052,-28028,-27004,-25980,-24956,
-23932,-22908,-21884,-20860,-19836,-18812,-17788,-16764,
-15996,-15484,-14972,-14460,-13948,-13436,-12924,-12412,
-11900,-11388,-10876,-10364, -9852, -9340, -8828, -8316,
-7932, -7676, -7420, -7164, -6908, -6652, -6396, -6140,
-5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092,
-3900, -3772, -3644, -3516, -3388, -3260, -3132, -3004,
-2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980,
-1884, -1820, -1756, -1692, -1628, -1564, -1500, -1436,
-1372, -1308, -1244, -1180, -1116, -1052, -988, -924,
-876, -844, -812, -780, -748, -716, -684, -652,
-620, -588, -556, -524, -492, -460, -428, -396,
-372, -356, -340, -324, -308, -292, -276, -260,
-244, -228, -212, -196, -180, -164, -148, -132,
-120, -112, -104, -96, -88, -80, -72, -64,
-56, -48, -40, -32, -24, -16, -8, 0,
32124, 31100, 30076, 29052, 28028, 27004, 25980, 24956,
23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764,
15996, 15484, 14972, 14460, 13948, 13436, 12924, 12412,
11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316,
7932, 7676, 7420, 7164, 6908, 6652, 6396, 6140,
5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092,
3900, 3772, 3644, 3516, 3388, 3260, 3132, 3004,
2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980,
1884, 1820, 1756, 1692, 1628, 1564, 1500, 1436,
1372, 1308, 1244, 1180, 1116, 1052, 988, 924,
876, 844, 812, 780, 748, 716, 684, 652,
620, 588, 556, 524, 492, 460, 428, 396,
372, 356, 340, 324, 308, 292, 276, 260,
244, 228, 212, 196, 180, 164, 148, 132,
120, 112, 104, 96, 88, 80, 72, 64,
56, 48, 40, 32, 24, 16, 8, 0
};
//und hier die Methode welche uLaw zu linear konvertieren soll.
int CG711::decodeULaw(unsignedchar u_val)
{
return ulaw2linear_tab[u_val];
}
FireBird2002
29.09.2008, 17:32
Deine LUT ist unstetig, du beginst mit dem Interval ]-32124;0[ und ab 0 machst du mit ]32124;0[ umgedreht weiter. Du solltest ]0;32124[ verwenden.
Die Minus Werte bleiben aber in der Reihenfolge 32124;0 drin?
Deine LUT ist unstetig, du beginst mit dem Interval ]-32124;0[ und ab 0 machst du mit ]32124;0[ umgedreht weiter. Du solltest ]0;32124[ verwenden.
So obwohl ich das umgekehrt habe also im Moment so -32124;0 und 0;32124 habe ich dieses komische Rauschen aber keine Sprache.
Vllt. hab ich ja auch einen Fehler in der Art wie ich die Frames abspielen möchte. Dazu habe ich eine Klasse erstellt, welche im Konstruktor die WAVEFORMATEX Struktur initialisiert. Dann wird in einer weiteren Methode mein WaveHeader initialisiert. In der folgenden Methode Play, welcher der Buffer und die Größe als Parameter übergeben werden, wird dann die Ausgabe gemacht. Die Größe ist hier die strlen des Buffers.
Hier der Code der Play Methode:
bool CWaveOut::Play(char* szBuffer, UINT uSize)
{
char* p;
LPWAVEHDR lpWaveHdr = new WAVEHDR;
if(!lpWaveHdr)
return false;
p = (char*)malloc(uSize);
int iBuf = 0;
ZeroMemory(lpWaveHdr, sizeof(WAVEHDR));
char szErr[1024];
CG711* pG711 = new CG711();
for(int i = 0; i < uSize; i++)
{
if(pG711->decodeULaw(szBuffer[i]) > 0)
{
p[iBuf] = pG711->decodeULaw(szBuffer[i]);
iBuf++;
}
}
delete pG711;
pG711 = NULL;
lpWaveHdr->dwBufferLength = uSize;
lpWaveHdr->lpData = p;
m_mmr = waveOutPrepareHeader(m_hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
if(m_mmr)
{
waveOutGetErrorTextA(m_mmr, szErr, sizeof(szErr));
return false;
}
m_mmr = waveOutWrite(m_hWaveOut, lpWaveHdr, sizeof(WAVEHDR));
if(m_mmr)
{
waveOutGetErrorTextA(m_mmr, szErr, sizeof(szErr));
return false;
}
if(waveOutUnprepareHeader(m_hWaveOut, lpWaveHdr, sizeof(WAVEHDR))== WAVERR_STILLPLAYING)
{
Sleep(100);
}
}
Also ich habe das jetzt soweit gelöst, allerdings nutze ich jetzt DirectX für das Sound Capturing und empfangen der Daten.
Allerdings ist das Versenden der Sprache noch ziemlich schlecht in der Qualität. Also ich gehe zum Versenden folgendermaßen vor.
Wenn die Methode mitbekommt dass Daten zum Versenden bereit liegen, dann sample ich das ganze down auf 8bit. Also die Einstellungen der Aufnahme sind nun 48000 hz bei 16bit.
Hier das Downsampling:
constint RATIO = (SAMPLERATE/8000);
constint size2 = (size/RATIO);
short* downsampledAudio = newshort;
[SIZE=2]signedlong summe = 0;
for(int i = 0; i < size; i++)
{
summe += rawData[i];
if((i%RATIO) == 0)
downsampledAudio[i/RATIO] = summe/RATIO;
summe = 0;
}
dann encodier ich es in uLaw
for(int i = 0; i < size2; i++)
newPacket.m_payload[i] = g711.encodeULaw(downsampledAudio[i]);
und versende es. Das was auf der anderen Seite ankommt hört sich allerdings noch ein bißchen wie Darth Vader an. Wie kann ich die Qualität hier noch verbessern?
Gruß
Karsten
FireBird2002
07.10.2008, 19:23
Das kann nur nach Darth Vader klingen:
Durch das downsample entsorgst du die Informationen, die du durch µ-Law gerade erhalten wolltest.
Das Encoding kannst du nicht über eine Tabelle mache. AFAIK ist die µ-Law-Kennlinie abschnittsweise linear, du kannst also für jeden Abschnitt eine einfache Umrechnungsformel entwickeln.
Also verstehe ich das richtig? Das Downsampling einfach weglassen?
Das Encoding mache ich über folgende Funktion
unsignedchar encodeULaw(short pcm_val)
{
short mask;
short seg;
unsignedchar uval;
pcm_val = pcm_val >> 2;
if (pcm_val < 0)
{
pcm_val = -pcm_val;
mask = 0x7F;
}
else
{
mask = 0xFF;
}
if ( pcm_val > CLIP ) pcm_val = CLIP;
pcm_val += (BIAS >> 2);
seg = search(pcm_val, seg_uend, 8);
if (seg >= 8)
return (unsignedchar) (0x7F ^ mask);
else
{
uval = (unsignedchar) (seg << 4) | ((pcm_val >> (seg + 1)) & 0xF);
return (uval ^ mask);
}
}
Also ich habe das jetzt soweit gelöst, allerdings nutze ich jetzt DirectX für das Sound Capturing und empfangen der Daten.
Allerdings ist das Versenden der Sprache noch ziemlich schlecht in der Qualität. Also ich gehe zum Versenden folgendermaßen vor.
Wenn die Methode mitbekommt dass Daten zum Versenden bereit liegen, dann sample ich das ganze down auf 8bit. Also die Einstellungen der Aufnahme sind nun 48000 hz bei 16bit.
Das was auf der anderen Seite ankommt hört sich allerdings noch ein bißchen wie Darth Vader an. Wie kann ich die Qualität hier noch verbessern?
Es reicht, wenn du auf 12 Bit konvertierst (einfach die 4 LSB herausrotieren:
WORD* data;
for (int i=0; i<PACKET_SIZE; i++)
data(i) = data(i) >> 4;
(Sorry, hab gerade keine eckigen Klammern greifbar ;-), das ist *kein* Downsampling). Wenn du die 12 Bits als Index in eine vorberechnete Tabelle nimmst, hast du gleich einen µ-/a-Law-Wert.
Du kannst die Konvertierung auch "zu Fuß" machen, das µ- bzw. a-Law ist ja simpel. Es kostet halt Zeit, während dich die LUT mit 4096 Einträgen statisch 4kb kostet.
Was das *wirkliche* Downsampling angeht -- das uLaw wie das aLaw sind für Übertragungsraten bis 3400Hz ausgelegt, die Samplingfrequenz sollte 8kHz betragen (das ist ISDN-Telefonqualität und erzeugt einen statischen Datenstrom von 64.000bit/s). Zum Downsampling sollte optimalerweise eine Fensterung verwendet werden (sinc bzw. Gauss). Wenn du mit 48kHz samplest, ist das einfach zu machen, du hast ein ganzzahliges Verhältniss zwischen Eingangs- und Ausgangsfrequenz (nämlich 6). Das macht die Fensterung simpel. In diesem Fall läuft es darauf hinaus:
Z(p) = (1 / m) * (a0 Q(6p) + a1 Q(6p+1) + a2 Q(6p+2) + a3 Q(6p+3) + a4 Q(6p+4) + a5 Q(6p+5))
dabei ist:
Z das Zielsample
Q das Array der Quellsamples.
a ist das Array mit den Fensterungskoeffizienten
m ist die Summe aller Koeffizienten.
p ist die Laufvariable.
Als Zwischenvariable sollte ein möglichst großer Datentyp verwendet werden, z.B. ein DWORD. Das Endergebnis entspricht vom Datentyp dem Eingangstyp (b.h. schiebst du 8Bit herein, kommt auch ein 8Bit Zielwert heraus). Das Zielarray ist in diesem Fall um den Faktor 6 kleiner.
Vorschlag für die Fensterungskoeffzienten:
a = (1, 4, 12, 12, 4, 1)
m = 34
Ich hoffe, das hilft weiter.
Wie kommt man denn auf die Fensterungskoeffizienten?
Was ich jetzt auch nicht so ganz verstehe, mach ich das erste downsampling auf 12 kBit denn vor der Fensterung noch oder ist das jetzt überflüssig. Is mir gerade nich so ganz klar.
Und wenn ich die 2te Formel durchgearbeitet habe, dann habe ich bereits in uLaw encodiert und kann das Packet versenden?
Was ich jetzt auch nicht so ganz verstehe, mach ich das erste downsampling auf 12 kBit denn vor der Fensterung noch oder ist das jetzt überflüssig. Is mir gerade nich so ganz klar.
Und wenn ich die 2te Formel durchgearbeitet habe, dann habe ich bereits in uLaw encodiert und kann das Packet versenden?
Also, die uLaw-Kodierung kommt zuletzt. Davor rechnest du am besten mit den Originaldaten.
Die zweite Funktion ist die Fensterungsfunktion. Sie ist so ausgelegt, daß sie eigentlich einer Laplace-Transformation entsprechen sollte. Da wir hier aber keine komplexwertigen Funktionen haben (bzw. uns der Phasengang nicht interessiert), sieht die Fensterungsfunktion ähnlich einer gauss'schen Glockenkurve (oder einer sinc-Funktion) aus. Im Grunde ist es eine gewichtete Mittelwertsberechnung. Die Elemente a0 und a5 liegen am weitesten vom (gedachten) Samplepunkt entfernt, fließen daher auch nur zu einem geringen Teil in die Berechnung an. Die Koeffizentenwerte 1, 4 und 14 geben die Gewichtung an, d.h. die in der Mitte liegenden Samples werden bevorzugt, dies ist eine "Weichzeichnung" des Samples, senkt aber auch das Quantisierungsrauschen - die Verständlichkeit steiht an. Du könntest, um noch bessere Ergebnisse zu erzielen, die Fensterung auch über 10 oder 16 Samples laufen lassen, aber das geht auf die Rechenzeit. Ich habe das Fensterintervall auf die minimale Fensterbreite gesetzt, so daß die Zielsamples nicht zum Aliasing neigen.
Die Kodierung zum uLaw findet danach statt: Also, 4 Bits rausrotieren und dann in der Lookuptable nachschauen. Wichtig ist dabei noch, daß du die Normalisierung beachten mußt: Im Gegensatz zum uLaw sind 16Bit Samples normalerweise signed, haben also ein Vorzeichen.
Wie muss denn die Lut aussehen?
Habe über google diese Lut gefunden, ist diese korrekt?
{0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
Oder arbeite ich mit der Lut die weiteroben aufgeführt ist?
Obwohl ich das so verstanden habe das diese nur für das decodieren ist.
Nochmal ich, bin gerade dabei die Fensterungsfunktion zu verstehen und sie zu implementieren. Jetzt ist mir aufgefallen da fehlt es mir auch noch am Verständnis. Wenn ich die Fensterungsfunktion wie beschrieben definiere
DWORD dwSource[DataSize]
for(int p = 0; p < DataSize; p++)
{
dwSource[p] = (1/m) * (a[0] * Q[6*p] + a[1] * Q[6 * p + 1] + a[2] * Q[6 * p + 2]
+ a[3] * Q[6 * p + 3] + a[4] * Q[6 * p + 4] + a[5] * Q[6 * p + 5]);
}
Dann muss es doch zu einem Puffer Überlauf kommen? Habe ich die Funktion überhaupt richtig verstanden?
Oder muss ich die DataSize für die Iteration auch durch 6 teilen?
Nochmal ich, bin gerade dabei die Fensterungsfunktion zu verstehen und sie zu implementieren. Jetzt ist mir aufgefallen da fehlt es mir auch noch am Verständnis. Wenn ich die Fensterungsfunktion wie beschrieben definiere
DWORD dwSource[DataSize]
for(int p = 0; p < DataSize; p++)
{
dwSource[p] = (1/m) * (a[0] * Q[6*p] + a[1] * Q[6 * p + 1] + a[2] * Q[6 * p + 2]
+ a[3] * Q[6 * p + 3] + a[4] * Q[6 * p + 4] + a[5] * Q[6 * p + 5]);
}
Dann muss es doch zu einem Puffer Überlauf kommen? Habe ich die Funktion überhaupt richtig verstanden?
Oder muss ich die DataSize für die Iteration auch durch 6 teilen?
Die Fensterungsfunktion dient dazu, die Ausgangsdaten, die als 48kHz-Audiostream vorliegen, in einen 8kHz-Audiostream umzuwandeln. Die Fensterung wird verwendet, um eine gewichtete Mittelwertsberechnung durchzuführen, was sich positiv auf das SNR (Signal-Noise-Ratio = Rauschabstand) auswirkt.
Der folgende Code macht dies, er rechnet einen n Bytes großen Datenstrom gemäß der Fensterung in einen n/6 großen Datenstrom um. Dazu wird ein Array übergeben (also genauer, ein Pointer auf ein Array). Nach der Funktion liegen die Zieldaten im gleichen Array vor, allerings nur in den ersten n/6 Bytes. Wichtig, der Code ist schon ein wenig optimiert, sprich, die Koeffizienten werden konstant verwendet, und anstatt diskreter Array-Zugriffe verwende ich Pointerarithmetik. Ich hoffe, du kommst damit klar, ansonsten kann ich das genauer erklären.
int ReduceBitrateFrom48kTo8k ( DWORD* pBuffer, int nBytesToConvert)
{
ASSERT ( (nBytesToConvert % 6 ) == 0 );
DWORD *pSrc = pBuffer;
DWORD *pDst = pBuffer;
for ( int c = 0; c < (nBytesToConvert / 6); c++)
{
DWORD val = 0;
val = *pSrc++;
val += *pSrc++ * 4;
val += *pSrc++ * 14;
val += *pSrc++ * 14;
val += *pSrc++ * 4;
val += *pSrc++;
*pDst++ = val / 38;
}
return (pDst - pBuffer);
}
Die Funktion gibt die Anzahl der gültigen Samplewerte im Puffer zurück, die Koeffizienten sind konstant, um zusätzliche (und unnötige) Arrayzugriffe zu vermeiden. Die Laufzeit ist proportional zu nBytesToConvert und skaliert linear.
Die LUT, die du präsentierst, sieht eher nach einer Skalierungs-LUT aus. Die eigentliche LUT sollte 4096 Werte groß sein (LUT steht für LookUp-Table), für jeden möglichen 12-Bit-Eingangswert sollte sie einen a- bzw. µ-Law-kodiertes Byte auswerfen.
Wenn man die LUTs nicht im Netz findet, kann man sich ein kleines Hilfsprogramm schreiben, das eine solche generiert, das sollte in einer Skriptsprache oder in C nicht mehr als einen 20-Zeiler darstellen. Die Idee dabei ist ja, sich die Werte vorgenerieren zu lassen, damit man das nicht zur Laufzeit tun muß.
Morgen Pukys,
jetzt hab ich es kapiert:D.
Zumindest das mit der Fensterung.
Eine Frage hätte ich da aber noch, gibt es irgendwas was man beim erzeugen der LUT für u/a Law beachten muss bzw. muss ich mit speziellen Werten arbeiten?
Jetzt habe ich die Methode implementiert aber die Qualität ist um ein vielfaches schlechter geworden.
Ich habe allerdings die uLaw über die LUT noch nicht integriert sondern mache das noch über die encode Methode von mir.
EDIT:
Also ich muss ehrlich gestehen, ich weiß nicht wie ich mit den Informationen aus der ITU T Doku die LUT erstellen muss.
So dein Algorithmus scheint zu funktionieren. Allerdings schien mein uLaw Encoding nicht ganz korrekt zu sein.
Habe das ganze jetzt mal so angepasst, dass ich die mathematische Formel durchlaufen lasse, auch wenn es etwas mehr performance kostet. Weiß immer noch nicht wie die LUT zu erstellen ist.
Hier mal das neue Encoding
constdouble x = ( (double)pcm_val + 32768 ) / 65536;
constdouble u = 255;
constdouble fx = ( sgn(x) * log(1+u*x) ) / log( 1 + u );
return (unsignedchar)( 255 * fx );
Allerdings kommt der Sound jetzt so leise über das man am anderen Ende fasst gar nichts mehr versteht. So langsam fang ich echt an zu zweifeln. Weiß auch nicht mehr was man noch machen kann um die Packete hörbar zu übertragen. Echt komplex die Geschichte.
EDIT:
Ne mit der obigen Funktion ging das gar nicht.
Habe das uLaw jetzt noch mal mit Skalierung angepasst. Die Funktion sieht so aus
unsigned char encodeULaw(short pcm_val)
{
static int exp_lut[256] = {0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7};
int sign, exponent, mantissa;
unsigned char ulawbyte;
/* Get the sample into sign-magnitude. */
sign = (pcm_val >> 8) & 0x80; /* set aside the sign */
if (sign != 0) pcm_val = -pcm_val; /* get magnitude */
if (pcm_val > CLIP) pcm_val = CLIP; /* clip the magnitude */
/* Convert from 16 bit linear to ulaw. */
pcm_val = pcm_val + BIAS;
exponent = exp_lut[(pcm_val >> 7) & 0xFF];
mantissa = (pcm_val >> (exponent + 3)) & 0x0F;
ulawbyte = ~(sign | (exponent << 4) | mantissa);
#ifdef ZEROTRAP
if (ulawbyte == 0) ulawbyte = 0x02; /* optional CCITT trap */
#endif
return(ulawbyte);
}
Damit ist die Soundquali um einiges besser aber es ist immer noch ein ziemlich regelmäßiges, leicht störendes Knacken drin.
Aber erstmal großes Danke schön an Pukys. Dein Downsampling ist schon mal wunderbar und hat einiges an Besserung gebracht. Danke für die Mühe mir das so zu erklären und
näher zu bringen. Ohne deine Anstöße wäre ich jetzt wahrscheinlich schon stark am verzweifeln:D
vBulletin® v3.8.6, Copyright ©2000-2012, Jelsoft Enterprises Ltd.