die Verarbeitung eines audio-wav-Datei mit C
Arbeite ich an der Verarbeitung der amplitude einer wav-Datei und Skalierung durch einige decimal-Faktor. Ich bin versucht, wickeln Sie meinen Kopf herum, wie zu Lesen und neu-schreiben der Datei in ein memory-effizienten Weg, während auch versuchen, anzugehen, die Nuancen der Sprache (ich bin neu in C). Die Datei kann entweder ein 8 - oder 16-bit-format. Die Art, wie ich dachte, dies zu tun ist durch die erste Lesung der header-Daten in einige vordefinierte struct, und dann die Verarbeitung der eigentlichen Daten in einer Schleife, wo ich lese ein Stück von Daten in einen Puffer, tun, was nötig ist, um es, und dann schreiben Sie es an die Ausgabe.
#include <stdio.h>
#include <stdlib.h>
typedef struct header
{
char chunk_id[4];
int chunk_size;
char format[4];
char subchunk1_id[4];
int subchunk1_size;
short int audio_format;
short int num_channels;
int sample_rate;
int byte_rate;
short int block_align;
short int bits_per_sample;
short int extra_param_size;
char subchunk2_id[4];
int subchunk2_size;
} header;
typedef struct header* header_p;
void scale_wav_file(char * input, float factor, int is_8bit)
{
FILE * infile = fopen(input, "rb");
FILE * outfile = fopen("outfile.wav", "wb");
int BUFSIZE = 4000, i, MAX_8BIT_AMP = 255, MAX_16BIT_AMP = 32678;
//used for processing 8-bit file
unsigned char inbuff8[BUFSIZE], outbuff8[BUFSIZE];
//used for processing 16-bit file
short int inbuff16[BUFSIZE], outbuff16[BUFSIZE];
//header_p points to a header struct that contains the file's metadata fields
header_p meta = (header_p)malloc(sizeof(header));
if (infile)
{
//read and write header data
fread(meta, 1, sizeof(header), infile);
fwrite(meta, 1, sizeof(meta), outfile);
while (!feof(infile))
{
if (is_8bit)
{
fread(inbuff8, 1, BUFSIZE, infile);
} else {
fread(inbuff16, 1, BUFSIZE, infile);
}
//scale amplitude for 8/16 bits
for (i=0; i < BUFSIZE; ++i)
{
if (is_8bit)
{
outbuff8[i] = factor * inbuff8[i];
if ((int)outbuff8[i] > MAX_8BIT_AMP)
{
outbuff8[i] = MAX_8BIT_AMP;
}
} else {
outbuff16[i] = factor * inbuff16[i];
if ((int)outbuff16[i] > MAX_16BIT_AMP)
{
outbuff16[i] = MAX_16BIT_AMP;
} else if ((int)outbuff16[i] < -MAX_16BIT_AMP) {
outbuff16[i] = -MAX_16BIT_AMP;
}
}
}
//write to output file for 8/16 bit
if (is_8bit)
{
fwrite(outbuff8, 1, BUFSIZE, outfile);
} else {
fwrite(outbuff16, 1, BUFSIZE, outfile);
}
}
}
//cleanup
if (infile) { fclose(infile); }
if (outfile) { fclose(outfile); }
if (meta) { free(meta); }
}
int main (int argc, char const *argv[])
{
char infile[] = "file.wav";
float factor = 0.5;
scale_wav_file(infile, factor, 0);
return 0;
}
Ich bin immer unterschiedlichen Dateigrößen am Ende (von 1k oder so, für eine 40Mb Datei), und ich vermute, dies ist aufgrund der Tatsache, dass ich Schreibe einen ganzen Puffer an den Ausgang, auch wenn die Datei beendet haben, vor dem Befüllen die gesamte Puffergröße. Auch die Ausgabe-Datei ist Durcheinander - nicht spielen oder öffnen - also ich bin wahrscheinlich macht die ganze Sache falsch. Irgendwelche Tipps, wo ich bin, vermasselt wird groß sein. Danke!
die Ausgabe ist größer
InformationsquelleAutor sa125 | 2010-03-16
Du musst angemeldet sein, um einen Kommentar abzugeben.
1 Sie Lesen bytes, anstelle von 16-bit-Proben in diesem else Zweig:
2 brauchen Sie nicht zu sättigen sich die Werte bei Skalierung, z.B. original-16-bit-sample = 32000 und Faktor = 1.5-wrap-around-der integer-Wert statt zu spannen, um das maximum von 32767.
3, die Sie nicht Blick auf das RIFF und andere Header überhaupt. In WAV-Dateien ist es möglich, dass die audio-Daten ist, gefolgt von einigen informativen Fußzeilen oder vorangestellt zusätzliche Header. Oder in anderen Worten: Ihre
header
struct ist zu statisch. Lesen Sie auch das WAV-format aus der Datei anstatt einen parameter zu sagen, dass es 8-bit-samples.4 Dies einfach nicht passieren wird:
8-bit/16-bit-Werte nie größer als 255/32768 außer, wenn Ihr computer fügt einige magic-bits in den Speicher, wenn der Integer-overflows 😛
- Und audio-Beispiele sind unterzeichnet, so werden die Bereiche -128;127 und -32768;32767. Überlauf-überprüfung muss erfolgen, in der die Multiplikation Ausdruck. Sie sind auch die Annahmen, auf die Gleitkomma-zu-Ganzzahl-Rundung-Modus ist konfigurierbar und sollte berücksichtigt werden. So etwas wie
if(roundf(factor * inbuff16[i]) > 32767 || roundf(factor * inbuff16[i]) < -32768)
vielleicht.5 Sie nicht speichern Sie das Ergebnis
fread
, so schreiben Sie zu viele Proben, um die Ausgabe-Datei.6 Und als letzten Punkt, sind Sie das Rad neu erfinden. Wie lange, wie dies für das lernen, es ist okay. Sonst sollten Sie nutzen bestehende Bibliotheken.
das ist ein tolles feedback, ich werde versuchen, diese Dinge
re: Punkt 3, können Sie auch nicht machen Annahmen, basierend auf der Inspektion der Ausgabe Ihrer Lieblings-wave-editor, wie Sie alle haben Macken. Offensichtlich sehr viel von der Arbeit in libsndfile beteiligten arbeiten, um Merkwürdigkeiten in verschiedene wave-Editoren. Wenn Sie sind komfortabel mit der libsndfile-Lizenz, all das reduziert sich auf ein paar sf_read_floats und sf_write_floats mit einigen initialisieren Zeug geworfen.
InformationsquelleAutor AndiDog
Es ist viel besser, Bibliotheken zum Lesen und schreiben von sound-Dateien. E. g.
libsndfile
. Die web-Seite hat eine Liste der "ähnlichen Projekte" können Sie sich auch anschauen. Diesndfile-tools
könnte gut sein, code-Beispiele, um zu lernen, wie die Bibliothek zu benutzen.InformationsquelleAutor Craig McQueen
Ich würde empfehlen, sich auf die original-Datei und die Ausgabe-Datei in einem hex-editor, um zu sehen, wenn Sie das neu-schreiben der Daten ordnungsgemäß. Wenn Sie die resultierende Datei nicht Abspielen oder öffnen, sind die Chancen auf den header der output-Datei ist nicht korrekt.
Andere option ist, um Ihre audio-Verarbeitung logic und einfach Lesen Sie in der Quell-Datei auf Ihrem internen Puffer und schreibt Sie in eine Datei. Wenn Ihr code erzeugen kann, die eine gültige, funktionierende output-Datei auf diese Weise, dann können Sie das problem einzugrenzen, um die Verarbeitung code.
Können Sie auch wollen, beginnen Sie mit einer kleineren Datei als 40Mb. Wenn nichts anderes, machen Sie eine Kopie dieser Eingabe-Datei, und schneiden Sie es nach unten, um ein paar Sekunden audio. Eine kleinere Datei, die leichter zu manuell prüfen.
Edit: Die Aufrufe
fread()
undfwrite()
müssen die Rückgabewerte überprüft. Diese Funktionen geben die Anzahl der Elemente, die gelesen oder geschrieben werden, und wenn ein Anruf an die Funktion gibt einen Wert kleiner als erwartet, dann könnte dies die Quelle Ihrer Datei-Größe Unterschied.Auch, der zweite parameter
fread
ist in bytes. Deshalb, wenn Sie Lesen möchten-füllen Sie eine ganze Puffer, würden Sie brauchen, um etwas zu sagen, mehr wiefread(inbuff16, sizeof(inbuff16[0]), BUFSIZE, infile);
. Der aktuelle code wird nur gelesenBUFSIZE
bytes (die arbeiten für die 8-bit-Fall durch Zufall, aber ich würde empfehlen, es zu verändern, auch für Klarheit).InformationsquelleAutor bta
Diese folgende Zeile ist auch nicht erforderlich für das Lesen von WAV-Header (die header 48 Byte lang, anstatt der "standard" - 44):
InformationsquelleAutor Okko
Wenn möglich, möchten Sie vielleicht zu betrachten, die eine andere Sprache als C, es sei denn, es ist speziell für eine C-Anwendung.
InformationsquelleAutor Jonathan Cline IEEE