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 version(Windows){ 12 import core.sys.windows.windows; 13 }else version(Posix){ 14 import core.stdc.errno; 15 } 16 17 import libPCM.types; 18 import libPCM.common; 19 import libPCM.utility; 20 21 public: 22 /** 23 * Loads a *.pcm file into the memory. 24 */ 25 PCMFile loadPCMFile(immutable char* name, bool indivStreams = true){ 26 FILE* inputStream = fopen(name, "rb"); 27 if(inputStream is null){ 28 import std.conv; 29 version(Windows){ 30 DWORD errorCode = GetLastError(); 31 }else version(Posix){ 32 int errorCode = errno; 33 } 34 35 throw new AudioFileException("File access error! Error number: " ~ to!string(errorCode)); 36 } 37 PCMFile file; 38 void* buffer; 39 char* tagData; 40 fread(&file.header, PCMHeader.sizeof, 1, inputStream); 41 size_t tagData_l = (file.header.author_l + file.header.comment_l + file.header.copyright_l + file.header.name_l) * 4; 42 if(tagData_l){ 43 tagData = cast(char*)malloc(tagData_l); 44 fread(tagData, tagData_l, 1, inputStream); 45 file.loadTagData(tagData); 46 free(tagData); 47 } 48 if(indivStreams){ 49 int wordlength = getWordLength(file.header.codecType); 50 size_t sampleSize = (file.header.length * wordlength) / 8; 51 sampleSize += (file.header.length * wordlength) % 8 ? 1 : 0; 52 //allocate memory for the individual WaveData 53 for(int i ; i < file.header.numOfChannels ; i++){ 54 55 file.waveData ~= new WaveData(file.header.length, file.header.sampleRate, file.header.codecType, sampleSize); 56 } 57 buffer = malloc(sampleSize * file.header.numOfChannels); 58 fread(buffer, sampleSize, file.header.numOfChannels, inputStream); 59 size_t bufferOffset; 60 switch(wordlength){ 61 case 16: 62 for(size_t i ; i < sampleSize; i++){ 63 for(int j ; j < file.header.numOfChannels ; j++){ 64 *cast(ushort*)((file.waveData[j].data.ptr) + i) = *(cast(ushort*)(buffer) + bufferOffset); 65 bufferOffset++; 66 } 67 } 68 break; 69 case 24, 12: 70 for(size_t i ; i < sampleSize; i++){ 71 for(int j ; j < file.header.numOfChannels ; j++){ 72 *cast(ubyte*)((file.waveData[j].data.ptr) + i) = *cast(ubyte*)(buffer + bufferOffset); 73 bufferOffset++; 74 *cast(ubyte*)((file.waveData[j].data.ptr) + i) = *cast(ubyte*)(buffer + bufferOffset); 75 bufferOffset++; 76 *cast(ubyte*)((file.waveData[j].data.ptr) + i) = *cast(ubyte*)(buffer + bufferOffset); 77 bufferOffset++; 78 } 79 } 80 break; 81 case 32: 82 for(size_t i ; i < sampleSize; i++){ 83 for(int j ; j < file.header.numOfChannels ; j++){ 84 *cast(uint*)((file.waveData[j].data.ptr) + i) = *(cast(uint*)(buffer) + bufferOffset); 85 bufferOffset++; 86 } 87 } 88 break; 89 default: 90 for(size_t i ; i < sampleSize; i++){ 91 for(int j ; j < file.header.numOfChannels ; j++){ 92 *cast(ubyte*)((file.waveData[j].data.ptr) + i) = *cast(ubyte*)(buffer + bufferOffset); 93 bufferOffset++; 94 } 95 } 96 break; 97 } 98 free(buffer); 99 }else{ 100 int wordlength = getWordLength(file.header.codecType); 101 size_t sampleSize = (file.header.length * wordlength) / 8; 102 sampleSize += (file.header.length * wordlength) % 8 ? 1 : 0; 103 buffer = malloc(sampleSize * file.header.numOfChannels); 104 fread(buffer, sampleSize, file.header.numOfChannels, inputStream); 105 memCpy(file.startOfData.ptr, buffer, sampleSize * file.header.numOfChannels); 106 free(buffer); 107 } 108 fclose(inputStream); 109 return file; 110 } 111 /** 112 * Loads a *.wav file into the memory. 113 */ 114 WavFile loadWavFile(immutable char* name, bool indivStreams = true){ 115 FILE* inputStream = fopen(name, "rb"); 116 if(inputStream is null){ 117 import std.conv; 118 version(Windows){ 119 DWORD errorCode = GetLastError(); 120 }else version(Posix){ 121 int errorCode = errno; 122 } 123 throw new AudioFileException("File access error! Error number: " ~ to!string(errorCode)); 124 } 125 WavFile file; 126 WavHeader header; 127 void* buffer; 128 fread(&header, header.sizeof, 1, inputStream); 129 file.header = header; 130 buffer = malloc(file.header.subchunk2Size); 131 fread(buffer, file.header.subchunk2Size, 1, inputStream); 132 if(!indivStreams){ 133 memCpy(file.startOfData.ptr, buffer, file.header.subchunk2Size); 134 free(buffer); 135 return file; 136 } 137 file.waveData.length = file.header.numOfChannels; 138 if(file.header.numOfChannels == 1){ 139 CodecType codecType; 140 if(file.header.bitsPerSample == 8 && file.header.audioFormat == 1){ 141 codecType = CodecType.UNSIGNED8BIT; 142 }else if(file.header.bitsPerSample == 16 && file.header.audioFormat == 1){ 143 codecType = CodecType.SIGNED16BIT; 144 } 145 file.waveData[0] = new WaveData(file.header.subchunk2Size * file.header.bitsPerSample / 8, file.header.sampleRate, codecType, file.header.subchunk2Size); 146 memCpy(buffer, file.waveData[0].data.ptr, file.header.subchunk2Size); 147 }else if(file.header.numOfChannels == 2){ 148 CodecType codecType; 149 if(file.header.bitsPerSample == 8 && file.header.audioFormat == 1){ 150 codecType = CodecType.UNSIGNED8BIT; 151 }else if(file.header.bitsPerSample == 16 && file.header.audioFormat == 1){ 152 codecType = CodecType.SIGNED16BIT; 153 } 154 file.waveData[0] = new WaveData(file.header.subchunk2Size * file.header.bitsPerSample / 16, file.header.sampleRate, codecType, file.header.subchunk2Size); 155 file.waveData[1] = new WaveData(file.header.subchunk2Size * file.header.bitsPerSample / 16, file.header.sampleRate, codecType, file.header.subchunk2Size); 156 size_t bufferOffset; 157 if(file.header.bitsPerSample == 8 && file.header.audioFormat == 1){ 158 for(size_t i ; i < file.waveData[0].length; i++){ 159 for(int j ; j < file.header.numOfChannels ; j++){ 160 *cast(ubyte*)(file.waveData[j].data.ptr + i) = *cast(ubyte*)(buffer + bufferOffset); 161 bufferOffset++; 162 } 163 } 164 }else if(file.header.bitsPerSample == 16 && file.header.audioFormat == 1){ 165 for(size_t i ; i < file.waveData[0].length ; i++){ 166 for(int j ; j < file.header.numOfChannels ; j++){ 167 *cast(ushort*)(file.waveData[j].data.ptr + i) = *cast(ushort*)(buffer + bufferOffset); 168 bufferOffset++; 169 } 170 } 171 } 172 } 173 fclose(inputStream); 174 free(buffer); 175 return file; 176 } 177 /** 178 * Stores a *.wav file. 179 */ 180 void storeWavFile(WavFile file, immutable char* name){ 181 FILE* outputStream = fopen(name, "wb"); 182 if(outputStream is null){ 183 import std.conv; 184 version(Windows){ 185 DWORD errorCode = GetLastError(); 186 }else version(Posix){ 187 int errorCode = errno; 188 } 189 throw new AudioFileException("File access error! Error number: " ~ to!string(errorCode)); 190 } 191 fwrite(&(file.header), WavHeader.sizeof, 1, outputStream); 192 if(file.startOfData.length){ 193 fwrite(file.startOfData.ptr, file.startOfData.length, 1, outputStream); 194 }else if(file.waveData.length == 1){ 195 fwrite(file.waveData[0].data.ptr, file.waveData[0].data.length, 1, outputStream); 196 } 197 fclose(outputStream); 198 } 199 /** 200 * Stores a *.pcm file. 201 */ 202 void storePCMFile(PCMFile file, immutable char* name){ 203 FILE* outputStream = fopen(name, "wb"); 204 if(outputStream is null){ 205 import std.conv; 206 version(Windows){ 207 DWORD errorCode = GetLastError(); 208 }else version(Posix){ 209 int errorCode = errno; 210 } 211 throw new AudioFileException("File access error! Error number: " ~ to!string(errorCode)); 212 } 213 fwrite(&(file.header), PCMHeader.sizeof, 1, outputStream); 214 if(file.startOfData.length){ 215 fwrite(file.startOfData.ptr, file.startOfData.length, 1, outputStream); 216 }else if(file.waveData.length == 1){ 217 fwrite(file.waveData[0].data.ptr, file.waveData[0].data.length, 1, outputStream); 218 } 219 fclose(outputStream); 220 }