WAVE odczyt i zapis.

0

Witam.
Mam problem natury takiej, że gdy wczytuję plik .wav i później chcę go zapisać w takiej samej postaci to plik wyjściowy ma 44b no i niestety nie działa.
Nie jestem pewien czy po subchunk2Size nie ma jakichś danych lub czy pomiędzy coś nie pominąłem.
Pozdrawiam.

#include <iostream>
#include <fstream>

using namespace std;

struct wavHEADER
{
public :
	//wavHEADER() : Data(nullptr) {}
	//~wavHEADER() { delete[] Data; }
	char riff[4];
	int chunkSize;
	char wave[4];
	char fmt[4];
	int subchunk1Size;
	short int audioFormat;
	short int numChannels;

	int sampleRate;
	int ByteRate;
	short int BlockAlign;
	short int BitsPerSample;

	char SubChunk2ID[4];
	int subchunk2Size;
	//byte* Data;
};

//stałe
static const uint32_t size_ui32 = sizeof(uint32_t);
static const uint32_t size_ui16 = sizeof(uint16_t);


int main()
{
	//wczytanie pliku
	ifstream file("input.wav",ios::in | ios::binary); 
	wavHEADER wavFile;

	if (file.good()) {
		file.read(wavFile.riff, 4);
		file.read(reinterpret_cast<char*>(&wavFile.chunkSize), size_ui32);
		file.read(wavFile.wave, 4);
		file.read(wavFile.fmt, 4);
		file.read(reinterpret_cast<char*>(&wavFile.subchunk1Size), size_ui32);
		file.read(reinterpret_cast<char*>(&wavFile.audioFormat), size_ui16);
		file.read(reinterpret_cast<char*>(&wavFile.numChannels), size_ui16);
		file.read(reinterpret_cast<char*>(&wavFile.sampleRate), size_ui32);
		file.read(reinterpret_cast<char*>(&wavFile.ByteRate), size_ui32);
		file.read(reinterpret_cast<char*>(&wavFile.BlockAlign), size_ui16);
		file.read(reinterpret_cast<char*>(&wavFile.BitsPerSample), size_ui16);
		file.read(wavFile.SubChunk2ID, 4);
		file.read(reinterpret_cast<char*>(&wavFile.subchunk2Size), size_ui32);
		//wavFile.data = new byte[wavFile.subchunk2Size];
		//file.read(reinterpret_cast<char*>(wavFile.data), sizeof(wavFile.subchunk2Size));
		file.close();
	}
	
	cout << "RIFF: " << wavFile.riff[0] << wavFile.riff[1] << wavFile.riff[2] << wavFile.riff[3] << endl;
	cout << "chunkSize: " << wavFile.chunkSize << endl;
	cout << "wave: " << wavFile.wave[0] << wavFile.wave[1] << wavFile.wave[2] << wavFile.wave[3] << endl;
	cout << "fmt: " << wavFile.fmt[0] << wavFile.fmt[1] << wavFile.fmt[2] << wavFile.fmt[3] << endl;
	cout << "subchunk1Size: " << wavFile.subchunk1Size << endl;
	cout << "audioFormat: " << wavFile.audioFormat << endl;
	cout << "numChannels: " << wavFile.numChannels << endl;
	cout << "sampleRate: " << wavFile.sampleRate << endl;
	cout << "ByteRate: " << wavFile.ByteRate << endl;
	cout << "BlockAlign: " << wavFile.BlockAlign << endl;
	cout << "BitsPerSample: " << wavFile.BitsPerSample << endl;
	cout << "data: " << wavFile.SubChunk2ID[0] << wavFile.SubChunk2ID[1] << wavFile.SubChunk2ID[2] << wavFile.SubChunk2ID[3] << endl;
	cout << "subchunk2Size: " << wavFile.subchunk2Size << endl;


	//zapisanie do pliku
	ofstream file2("output.wav", ios::binary | ios::app | ios::ate);
	if (file2.good())
	{
		file2.write(wavFile.riff, 4);
		file2.write(reinterpret_cast<char*>(&wavFile.chunkSize), size_ui32);
		file2.write(wavFile.wave, 4);
		file2.write(wavFile.fmt, 4);
		file2.write(reinterpret_cast<char*>(&wavFile.subchunk1Size), size_ui32);
		file2.write(reinterpret_cast<char*>(&wavFile.audioFormat), size_ui16);
		file2.write(reinterpret_cast<char*>(&wavFile.numChannels), size_ui16);
		file2.write(reinterpret_cast<char*>(&wavFile.sampleRate), size_ui32);
		file2.write(reinterpret_cast<char*>(&wavFile.ByteRate), size_ui32);
		file2.write(reinterpret_cast<char*>(&wavFile.BlockAlign), size_ui16);
		file2.write(reinterpret_cast<char*>(&wavFile.BitsPerSample), size_ui16);
		file2.write(wavFile.SubChunk2ID, 4);
		file2.write(reinterpret_cast<char*>(&wavFile.subchunk2Size), size_ui32);
		//wavFile.data = new byte[wavFile.subchunk2Size];
		//file.read(reinterpret_cast<char*>(wavFile.data), sizeof(wavFile.subchunk2Size));
		file.close();
	}

	system("pause");
}




1

i później chcę go zapisać w takiej samej postaci to plik wyjściowy ma 44b

No a ile ma mieć, jeśli nie zapisujesz nic więcej poza nagłówkiem?

https://4programmers.net/Forum/C_i_C++/247347-odczyt_wav?p=1113605#id1113605 <--- tu masz przykład kodu czytającego (poprawnie) pliki .wav (między blokiem 'fmt ' a 'data' mogą występować inne bloki. Twój kod to ignoruje i czyta na rympał).

0

@_0x666_: wiem, że ignoruje to, robię to specjalnie na razie, ale na razie działam na jednym pliku i jakoś to idzie ponieważ to sprawdzam cout'em.
Mam jeszcze pytanie, gdybym chciał wyświetlić zawartość wavFile.data powiedzmy w postaci binarnej (nie całą oczywiście, jakiś kawałek) to czym powinienem się zainteresować?
Myślałem, że tym sposobem to nie zadziała, ale jednak się udało:

#include <iostream>
#include <fstream>

using namespace std;

struct wavHEADER
{
public :
	char riff[4];
	int chunkSize;
	char wave[4];
	char fmt[4];
	int subchunk1Size;
	short int audioFormat;
	short int numChannels;

	int sampleRate;
	int ByteRate;
	short int BlockAlign;
	short int BitsPerSample;

	char SubChunk2ID[4];
	int subchunk2Size;
	char* data;
};

//stałe
static const uint32_t size_ui32 = sizeof(uint32_t);
static const uint32_t size_ui16 = sizeof(uint16_t);


int main()
{
	//wczytanie pliku
	ifstream inFile("input.wav",ios::in | ios::binary); 
	wavHEADER wavFile;


	if (inFile.good()) {
		inFile.read(wavFile.riff, 4);
		inFile.read(reinterpret_cast<char*>(&wavFile.chunkSize), size_ui32);
		inFile.read(wavFile.wave, 4);
		inFile.read(wavFile.fmt, 4);
		inFile.read(reinterpret_cast<char*>(&wavFile.subchunk1Size), size_ui32);
		inFile.read(reinterpret_cast<char*>(&wavFile.audioFormat), size_ui16);
		inFile.read(reinterpret_cast<char*>(&wavFile.numChannels), size_ui16);
		inFile.read(reinterpret_cast<char*>(&wavFile.sampleRate), size_ui32);
		inFile.read(reinterpret_cast<char*>(&wavFile.ByteRate), size_ui32);
		inFile.read(reinterpret_cast<char*>(&wavFile.BlockAlign), size_ui16);
		inFile.read(reinterpret_cast<char*>(&wavFile.BitsPerSample), size_ui16);
		inFile.read(wavFile.SubChunk2ID, 4);
		inFile.read(reinterpret_cast<char*>(&wavFile.subchunk2Size), size_ui32);
		wavFile.data = new char[wavFile.subchunk2Size];									//data
		inFile.read(wavFile.data, wavFile.subchunk2Size);							   //data
		inFile.close();
	}


	//zapisanie do pliku
	ofstream outFile("output.wav", ios::binary | ios::app);
	if (outFile.good())
	{
		outFile.write(wavFile.riff, 4);
		outFile.write(reinterpret_cast<char*>(&wavFile.chunkSize), size_ui32);
		outFile.write(wavFile.wave, 4);
		outFile.write(wavFile.fmt, 4);
		outFile.write(reinterpret_cast<char*>(&wavFile.subchunk1Size), size_ui32);
		outFile.write(reinterpret_cast<char*>(&wavFile.audioFormat), size_ui16);
		outFile.write(reinterpret_cast<char*>(&wavFile.numChannels), size_ui16);
		outFile.write(reinterpret_cast<char*>(&wavFile.sampleRate), size_ui32);
		outFile.write(reinterpret_cast<char*>(&wavFile.ByteRate), size_ui32);
		outFile.write(reinterpret_cast<char*>(&wavFile.BlockAlign), size_ui16);
		outFile.write(reinterpret_cast<char*>(&wavFile.BitsPerSample), size_ui16);
		outFile.write(wavFile.SubChunk2ID, 4);
		outFile.write(reinterpret_cast<char*>(&wavFile.subchunk2Size), size_ui32);
		outFile.write(wavFile.data, wavFile.subchunk2Size);
		outFile.close();
	}
	system("pause");
}
1
static const uint32_t size_ui32 = sizeof(uint32_t);

inFile.read(reinterpret_cast<char*>(&wavFile.chunkSize), size_ui32);

Rozwlekle to piszesz. Nieczytelnie. Co jest złego w:

inFile.read((char*)&wavFile.chunkSize, 4);

skoro chunkSize ma z definicji cztery bajty.
Poza tym jest raczej liczbą bez znaku. W strukturze natomiast masz inta. Ale sajzof pobierasz z uint32_t. To już w ogóle dziwnie.

1

(...) gdybym chciał wyświetlić zawartość wavFile.data powiedzmy w postaci binarnej

Na pewno binarnej? :|

Popraw typy w wavHEADER. Żadne tam inty i shorty, tylko uint32_t i uint16_t.

0

@_0x666_: tak, będę chciał wykorzystać to w steganografii i zmienić najmniej znaczące bity. Dlatego chciałbym mieć to zapisane w systemie dwójkowym.
Czy dobrze to rozumiem, wavFile.data jest typu char więc jak zrobię bitset<8> wavFile.data[0] to dostanę ciąg bitów składający się na ten bajt tak ?
Wszystko o czym mówiliście wezmę pod uwagę gdy tylko przysiądę przy tym.

0

IMO najlepiej zdefiniować szablon funkcji pomocniczej i wszytko od razu będzie czytelniejsze:

template<class T>
istream& LoadBigEndian(istream& input, T& value)
{
     T tmp;
     input.read(reinterpret_cast<char*>(&tmp), sizeof(T));
     value = FromBigEndian(tmp);
     return input;
}

Ten szablon można udoskonalić, chodzi mi o sam koncept.

1

W WinAPI masz gotową strukturę WAVEFORMATEX którą wypełniasz i zapisujesz do pliku za jednym zamachem.

https://msdn.microsoft.com/en-us/library/dd757713(v=vs.85).aspx
https://msdn.microsoft.com/en-us/library/dd757676(v=vs.85).aspx

1

(...) więc jak zrobię bitset<8> wavFile.data[0] to dostanę ciąg bitów składający się na ten bajt tak ?

Jeśli masz na myśli bitset<8>(wavFile.data[0]), to tak.

1 użytkowników online, w tym zalogowanych: 0, gości: 1