1 /*
2  * libPCM by László Szerémi.
3  * Copyright under Boost License.
4  */
5 
6 module libPCM.file;
7 
8 import core.stdc.stdio;
9 import core.stdc.stdlib;
10 import std.stdio;
11 import std.conv;
12 version(Windows){
13 	import core.sys.windows.windows;
14 }else version(Posix){
15 	import core.stdc.errno;
16 }
17 
18 import libPCM.types;
19 import libPCM.common;
20 import libPCM.utility;
21 
22 public:
23 	/**
24 	 * Loads a *.pcm file into the memory.
25 	 */
26 	PCMFile loadPCMFile(immutable char* name){
27 		FILE* inputStream = fopen(name, "rb");
28 		if(inputStream is null){
29 			import std.conv;
30 			version(Windows){
31 				DWORD errorCode = GetLastError();
32 			}else version(Posix){
33 				int errorCode = errno;
34 			}
35 
36 			throw new AudioFileException("File access error! Error number: " ~ to!string(errorCode));
37 		}
38 		PCMFile file;
39 		void* buffer;
40 		char* tagData;
41 		fread(&file.header, PCMHeader.sizeof, 1, inputStream);
42 		size_t tagData_l = (file.header.author_l + file.header.comment_l + file.header.copyright_l + file.header.name_l) * 4;
43 		if(tagData_l){
44 			tagData = cast(char*)malloc(tagData_l);
45 			fread(tagData, tagData_l, 1, inputStream);
46 			file.loadTagData(tagData);
47 			free(tagData);
48 		}
49 		size_t sampleSize, sampleLength;
50 		version(x64){
51 			sampleLength = (file.header.length + file.header.length_h<<32);
52 			sampleSize = sampleLength * (getWordLength(file.header.codecType)/8);
53 		}else{
54 			sampleLength = file.header.length;
55 			sampleSize = sampleLength * (getWordLength(file.header.codecType)/8);
56 		}
57 
58 		file.data = new WaveData(sampleLength, file.header.sampleRate, file.header.codecType, sampleSize, file.header.numOfChannels);
59 
60 		fread(file.data.data.ptr, sampleSize, 1, inputStream);
61 
62 		fclose(inputStream);
63 		return file;
64 	}
65 	/**
66 	 * Loads a *.wav file into the memory.
67 	 */
68 	WavFile loadWavFile(immutable char* name){
69 		FILE* inputStream = fopen(name, "rb");
70 		if(inputStream is null){
71 			import std.conv;
72 			version(Windows){
73 				DWORD errorCode = GetLastError();
74 			}else version(Posix){
75 				int errorCode = errno;
76 			}
77 			throw new AudioFileException("File access error! Error number: " ~ to!string(errorCode));
78 		}
79 		WavFile file = new WavFile;
80 		void* buffer;
81 		fread(&file.riff, file.riff.sizeof, 1, inputStream);
82 		fread(&file.subchunk1, file.subchunk1.sizeof, 1, inputStream);
83 		fread(&file.subchunk2, file.subchunk2.sizeof, 1, inputStream);
84 
85 		uint sampleLength = file.subchunk2.subchunk2Size / file.subchunk1.numOfChannels / 
86 							(getWordLength(fromWAVAudioFormat(file.subchunk1.audioFormat, file.subchunk1.bitsPerSample)) / 8);
87 		file.data = new WaveData(sampleLength, to!float(file.subchunk1.sampleRate), fromWAVAudioFormat(file.subchunk1.audioFormat, file.subchunk1.bitsPerSample), 
88 							file.subchunk2.subchunk2Size, cast(ubyte)file.subchunk1.numOfChannels);
89 		fread(file.data.data.ptr, file.subchunk2.subchunk2Size,1 , inputStream);
90 		
91 		fclose(inputStream);
92 		free(buffer);
93 		return file;
94 	}
95 	/**
96 	 * Stores a *.wav file.
97 	 */
98 	void storeWavFile(WavFile file, immutable char* name){
99 		FILE* outputStream = fopen(name, "wb");
100 		if(outputStream is null){
101 			import std.conv;
102 			version(Windows){
103 				DWORD errorCode = GetLastError();
104 			}else version(Posix){
105 				int errorCode = errno;
106 			}
107 			throw new AudioFileException("File access error! Error number: " ~ to!string(errorCode));
108 		}
109 		fwrite(&(file.riff), WavHeaderMain.sizeof, 1, outputStream);
110 		fwrite(&(file.subchunk1), WavHeaderSubchunk1.sizeof, 1, outputStream);
111 		fwrite(&(file.subchunk2), WavHeaderSubchunk2.sizeof, 1, outputStream);
112 		fwrite(file.data.data.ptr, file.data.data.length, 1, outputStream);
113 		fclose(outputStream);
114 	}
115 	/**
116 	 * Stores a *.pcm file.
117 	 */
118 	void storePCMFile(PCMFile file, immutable char* name){
119 		FILE* outputStream = fopen(name, "wb");
120 		if(outputStream is null){
121 			import std.conv;
122 			version(Windows){
123 				DWORD errorCode = GetLastError();
124 			}else version(Posix){
125 				int errorCode = errno;
126 			}
127 			throw new AudioFileException("File access error! Error number: " ~ to!string(errorCode));
128 		}
129 		fwrite(&(file.header), PCMHeader.sizeof, 1, outputStream);
130 		fwrite(file.data.data.ptr, file.data.data.length, 1, outputStream);
131 		
132 		fclose(outputStream);
133 	}