RIFF-Wavebuffer mischen

Hroudtwolf

Mitglied
Servus zusammen,

Ich erzeuge in meiner Source 2 (manchmal auch mehrere) Wave-Buffer.
Nun möchte ich einen Downmix 2er Buffer berechnen, habe aber keine Ahnung wie ich das anstellen muss.

Hat jemand ein wenig Ahnung davon und kann mir eventuell genau erklären wie ich das machen muss ?

Ich bedanke mich im Vornherein.
Schöne Grüsse :)

Hroudtwolf


PS: Libraries möchte ich keine nutzen.
Ich wäre natürlich total dankbar für Beispiel-Sources (in C, Java oder einem Basic-Dialekt).
 
Zuletzt bearbeitet:
Sorry, wenn ich den Beitrag noch mal pushe.
Aber eventuell war meine Frage auch ungenügend erklärt.

Ich berechne mit meinem Programm Wave-Buffer, also quasi Wave-Dateien im Speicher.
Nun möchte ich zum Beispiel 2 dieser Wavebuffer zu einem mischen.
Mir ist jedoch der Algorythmus unbekannt mit dem ich das anstellen könnte.

Auch eine umfassende Suche im Weltnetz ergab keine Erfolge.

Ich wäre extrem dankbar für jede Hilfe und jeden Tip.


MfG

Wolf
 
Hallo,

im Prinzip musst du nur die zwei Signale beider waves miteinander addieren ...
Dabei musst du einen evtl. Überlauf beachten (da ja ein wav nur 8/16 bzw 24 bits per sample besitzt), d.h. wenn der Wert über den maximalen Amplitudenwert geht kannst du ihn entweder einfach abschneiden oder normalisieren. Folgendes Programm schneidet ihn einfach ab:

C:
#include <stdio.h>
#include <limits.h>
#include <string.h>

#define IS_WAV_LITTLE_44100_SAMPLED(t) \
	(t.sample_rate == 44100)
#define IS_WAV_16BIT_CODED(t) \
	(t.bits_per_sample == 16)
#define NUMBER_OF_SAMPLES 64

typedef unsigned int doubleword;
typedef unsigned short word;

typedef struct {
	doubleword riff;
	doubleword file_length;
	doubleword wave;
	doubleword fmt;
	doubleword fmt_length;
	word fmt_tag;
	word channels;
	doubleword sample_rate;
	doubleword bytes_per_second;
	word block_align;
	word bits_per_sample;
	doubleword header_sig;
	doubleword data_length;
} wave_header_t;

static void print_wave_info(wave_header_t* wave_header, char *name)
{
	printf("Wave header for file: %s:\n", name);
	printf("File length in bytes:\t\t%d\n", wave_header->file_length);
	printf("Sample rate:\t\t\t%d\n", wave_header->sample_rate);
	printf("Bits per sample:\t\t%d\n", wave_header->bits_per_sample);
	printf("Data block length in bytes:\t%d\n", wave_header->data_length);
	printf("---------------------------------------\n");
}

static void mix_wave(FILE **wave_fds, int greater_idx)
{
	short sample1[NUMBER_OF_SAMPLES];
	short sample2[NUMBER_OF_SAMPLES];
	short real_result[NUMBER_OF_SAMPLES];
	int result[NUMBER_OF_SAMPLES];
	int i;
	
	while (fread(sample1, sizeof(sample1), 1, wave_fds[greater_idx])) {
		if (fread(sample2, sizeof(sample2), 1, wave_fds[!greater_idx])) {
			for (i = 0; i < NUMBER_OF_SAMPLES; i++) {
				result[i] = sample1[i] + sample2[i];
				if (result[i] > SHRT_MAX)
					real_result[i] = SHRT_MAX;
				else if (result[i] < SHRT_MIN)
					real_result[i] = SHRT_MIN;
				else
					real_result[i] = (short) result[i];
			}
		}
		else {
			for (i = 0; i < NUMBER_OF_SAMPLES; i++)
				real_result[i] = sample1[i];
		}
		fwrite(real_result, sizeof(real_result), 1, wave_fds[2]);
	}
}

static int write_wave_header(FILE *out_wave_fd, wave_header_t *wave_headers, char *name)
{
	wave_header_t mix_wave_header;
	

	memcpy(&mix_wave_header, &wave_headers[0], sizeof(wave_header_t));
	
	mix_wave_header.data_length 
		= wave_headers[0].data_length > wave_headers[1].data_length ?
			wave_headers[0].data_length :
			wave_headers[1].data_length;
	mix_wave_header.file_length = mix_wave_header.data_length +
		sizeof(wave_header_t) - 8;
	print_wave_info(&mix_wave_header, name);

	return fwrite(&mix_wave_header, sizeof(wave_header_t), 1, out_wave_fd);
}

static int get_greater_wav(wave_header_t *wave_headers)
{
	return wave_headers[0].data_length > wave_headers[1].data_length ?
		0 :
		1;
}

static void cleanup(FILE **wave_fds, int size)
{
	int i;

	for (i = 0; i < size; i++)
		if(wave_fds[i])
			fclose(wave_fds[i]);
}

static int check_wave_files(wave_header_t *wave_headers, int size)
{
	int i;

	for (i = 0; i < size; i++) {
		if (!IS_WAV_16BIT_CODED(wave_headers[i])) {
			fprintf(stderr, "Error: Only support 16 bit coded waves\n");
			return -1;
		}
		if (!IS_WAV_LITTLE_44100_SAMPLED(wave_headers[i])) {
			fprintf(stderr, "Error: Only support 44100 HZ sampled waves\n");
			return -1;
		}
	}
	return 0;
}

int main(int argc, char **argv)
{
	FILE *wave_fds[3];
	int i;
	wave_header_t wave_headers[2];

	bzero(wave_fds, sizeof(wave_fds));
	if (argc != 4) {
		fprintf(stderr,
				"Usage: mix <in_file1.wav> <in_file2.wav> <out_file.wav>\n");
		goto err;
	}

	for (i = 1; i < argc; i++) {
		char *mode;
		if (i == argc - 1)
			mode = "w";
		else
			mode = "r";
		if (!(wave_fds[i - 1] = fopen(argv[i], mode))) {
			perror("Error in fopen()");
			goto err;
		}
		if (i < argc - 1) {
		    if (!fread(&wave_headers[i - 1], sizeof(wave_header_t), 1, wave_fds[i - 1])) {
				perror("Error read()");
    	    	goto err;
	    	}
			print_wave_info(&wave_headers[i - 1], argv[i]);
		}
	}

	if (!write_wave_header(wave_fds[2], wave_headers, argv[3])) {
		perror("Error in fwrite()");
		goto err;
	}
	if (check_wave_files (wave_headers, 2) < 0)
		goto err;

	mix_wave(wave_fds, get_greater_wav(wave_headers));
	cleanup(wave_fds, 3);
	return 0;
err:
	cleanup(wave_fds, 3);
	return 1;
}

Die Sache funktioniert für 16 bit / sample, stereo, und 44100 gesampelte PCM codierte wav- Dateien.
Aufruf:

Code:
mix in1.wav in2.wav out.wav

das Programm ist noch bisl von der Perfektion entfernt irgendwie sind nämlich im Output noch ein paar Knachser, es soll dir aber das Prinzip zeigen wies prinzipiell funktioniert. Wenn du fragen hast melde dich :)

Gruß,
RedWing
 
Zurück