Created
January 28, 2015 15:51
-
-
Save lalawue/3c9a210d9816767050b9 to your computer and use it in GitHub Desktop.
Read .aiff audio file format and save the raw data
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2015 lalawue | |
* | |
* This library is free software; you can redistribute it and/or modify it | |
* under the terms of the MIT license. See LICENSE for details. | |
*/ | |
#include <stdio.h> | |
#include <string> | |
#include <vector> | |
#include <math.h> | |
#include <stdlib.h> | |
using namespace std; | |
static const int SHORT_MAX = 0xFFFF/2; | |
unsigned long swapByteOrderULong(unsigned long org) { | |
unsigned long ret = 0; | |
unsigned char *p = (unsigned char *)&ret; | |
p[3] = (org & 0x000000FF); | |
p[2] = (org & 0x0000FF00) >> 8; | |
p[1] = (org & 0x00FF0000) >> 16; | |
p[0] = (org & 0xFF000000) >> 24; | |
return ret; | |
} | |
unsigned short swapByteOrderUShort(unsigned short org){ | |
return ((org & 0xFF00) >> 8) | ((org & 0x00FF) << 8); | |
} | |
signed short swapByteOrderShort(signed short org){ | |
return ((org & 0xFF00) >> 8) | ((org & 0x00FF) << 8); | |
} | |
# define FloatToUnsigned(f) ((unsigned long)(((long)(f - 2147483648.0)) + 2147483647L) + 1) | |
#ifndef HUGE_VAL | |
#define HUGE_VAL HUGE | |
#endif /*HUGE_VAL*/ | |
void ConvertToIeeeExtended(double num, char* bytes) | |
{ | |
int sign; | |
int expon; | |
double fMant, fsMant; | |
unsigned long hiMant, loMant; | |
if (num < 0) { | |
sign = 0x8000; | |
num *= -1; | |
} else { | |
sign = 0; | |
} | |
if (num == 0) { | |
expon = 0; hiMant = 0; loMant = 0; | |
} | |
else { | |
fMant = frexp(num, &expon); | |
if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */ | |
expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */ | |
} | |
else { /* Finite */ | |
expon += 16382; | |
if (expon < 0) { /* denormalized */ | |
fMant = ldexp(fMant, expon); | |
expon = 0; | |
} | |
expon |= sign; | |
fMant = ldexp(fMant, 32); | |
fsMant = floor(fMant); | |
hiMant = FloatToUnsigned(fsMant); | |
fMant = ldexp(fMant - fsMant, 32); | |
fsMant = floor(fMant); | |
loMant = FloatToUnsigned(fsMant); | |
} | |
} | |
bytes[0] = expon >> 8; | |
bytes[1] = expon; | |
bytes[2] = hiMant >> 24; | |
bytes[3] = hiMant >> 16; | |
bytes[4] = hiMant >> 8; | |
bytes[5] = hiMant; | |
bytes[6] = loMant >> 24; | |
bytes[7] = loMant >> 16; | |
bytes[8] = loMant >> 8; | |
bytes[9] = loMant; | |
} | |
# define UnsignedToFloat(u) (((double)((long)(u - 2147483647L - 1))) + 2147483648.0) | |
double ConvertFromIeeeExtended(unsigned char* bytes /* LCN */) | |
{ | |
double f; | |
int expon; | |
unsigned long hiMant, loMant; | |
expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); | |
hiMant = ((unsigned long)(bytes[2] & 0xFF) << 24) | |
| ((unsigned long)(bytes[3] & 0xFF) << 16) | |
| ((unsigned long)(bytes[4] & 0xFF) << 8) | |
| ((unsigned long)(bytes[5] & 0xFF)); | |
loMant = ((unsigned long)(bytes[6] & 0xFF) << 24) | |
| ((unsigned long)(bytes[7] & 0xFF) << 16) | |
| ((unsigned long)(bytes[8] & 0xFF) << 8) | |
| ((unsigned long)(bytes[9] & 0xFF)); | |
if (expon == 0 && hiMant == 0 && loMant == 0) { | |
f = 0; | |
} | |
else { | |
if (expon == 0x7FFF) { /* Infinity or NaN */ | |
f = HUGE_VAL; | |
} | |
else { | |
expon -= 16383; | |
f = ldexp(UnsignedToFloat(hiMant), expon-=31); | |
f += ldexp(UnsignedToFloat(loMant), expon-=32); | |
} | |
} | |
if (bytes[0] & 0x80) | |
return -f; | |
else | |
return f; | |
} | |
void | |
_loadFile(char *_fileName, char *out_file_name) | |
{ | |
// vector<float> _left; | |
// vector<float> _right; | |
// _left.clear(); | |
// _right.clear(); | |
printf("size of unsigned long=%ld\n", sizeof(unsigned long)); | |
FILE *fp; | |
if ((fp = fopen(_fileName,"rb")) == NULL){ | |
printf("can't open file:%s.\n", _fileName); | |
return ; | |
} | |
printf("reading file : %s\n", _fileName); | |
//read "FORM" chunk | |
char str[5]; | |
str[4] = 0; | |
fread(str,1,4,fp); | |
printf("%s\n", str); //Should be FORM | |
unsigned long size; | |
fread(&size, 4,1, fp); | |
size = swapByteOrderULong(size); | |
printf("size = 0x%lx(%ld bytes)\n", size,size); | |
//read "AIFF" formType tag | |
char formType[5]; | |
formType[4] = 0; | |
fread(formType,1,4,fp); | |
printf("%s\n", formType); | |
//chunks ("COMM", "SSND",etc). | |
char chunkName[5]; | |
chunkName[4] = 0; | |
fread(chunkName,1,4,fp); | |
printf("%s\n", chunkName); | |
fread(&size, 4,1, fp); | |
size = swapByteOrderULong(size); | |
printf("size = 0x%lx(%ld bytes)\n", size,size); | |
int prevPos = ftell(fp); | |
unsigned short channels = 0; | |
unsigned long sampleFrames = 0; | |
string cName = chunkName; | |
if (cName == "COMM") { | |
printf("COMM chunk dumping\n"); | |
{ //parse Comm chunk | |
unsigned short bitSize = 0; | |
unsigned char sampleRateBytes[10]; | |
fread(&channels, 2 ,1 , fp); | |
channels = swapByteOrderUShort(channels); | |
fread(&sampleFrames, 4, 1, fp); | |
sampleFrames = swapByteOrderULong(sampleFrames); | |
fread(&bitSize, 2, 1, fp); | |
bitSize = swapByteOrderUShort(bitSize); | |
fread(&sampleRateBytes, 1, 10, fp); | |
double sampleRate = ConvertFromIeeeExtended(sampleRateBytes); | |
printf("%d channels, %d bits, %.2f[Hz], %ld samples\n", channels, bitSize, sampleRate, sampleFrames); | |
double duration = (double)sampleFrames / sampleRate; | |
printf("%.2f [seconds]\n", duration); | |
} | |
} | |
fseek(fp,prevPos, SEEK_SET); | |
fseek(fp,size,SEEK_CUR); | |
chunkName[4] = 0; | |
fread(chunkName,1,4,fp); | |
printf("%s\n", chunkName); | |
fread(&size, 4,1, fp); | |
size = swapByteOrderULong(size); | |
printf("size = 0x%lx(%ld bytes)\n", size, size); | |
cName = chunkName; | |
if (cName == "SSND") { | |
printf("dumping SSND chunk\n"); | |
unsigned long offset = 0; | |
unsigned long blockSize = 0; | |
fread(&offset, 4, 1, fp); | |
fread(&blockSize, 4, 1, fp); | |
offset = swapByteOrderULong(offset); | |
blockSize = swapByteOrderULong(blockSize); | |
printf("offset = %ld, blockSize = %ld\n", offset, blockSize); | |
} | |
printf("loading buffers..."); | |
//if (channels == 1){ //assuming stereo only? | |
//ensure size. | |
signed short *samples = (short*)malloc(sizeof(short) * sampleFrames*channels); | |
fread(samples, 2, sampleFrames*channels, fp); | |
unsigned short *result = (unsigned short*)malloc(sizeof(*result) *sampleFrames*channels); | |
printf("sampleFrames = %ld, %ld\n", sampleFrames, sizeof(*result)); | |
for (int i = 0; i < sampleFrames*channels ; i++){ | |
//_stlbuffer.push_back(swapByteOrderShort(samples[i])); | |
// float val = swapByteOrderShort(samples[i]); | |
// val /= SHORT_MAX; | |
// val *= 0.99; //avoid clipping. | |
// if (0 == (i % 2)) { | |
// _left.push_back(val); | |
// } else { | |
// _right.push_back(val); | |
// } | |
result[i] = swapByteOrderShort(samples[i]); | |
} | |
{ | |
FILE *wfp = fopen(out_file_name, "wb"); | |
fwrite(result, sizeof(*result), sampleFrames*channels, wfp); | |
fclose(wfp); | |
} | |
//printf("STL Buffer array size = %lu\n", _stlbuffer.size()); | |
fclose(fp); | |
} | |
int main(int argc, char *argv[]) { | |
if (argc < 3) { | |
printf("%s aiff_file out_sample\n", argv[0]); | |
return 0; | |
} | |
_loadFile(argv[1], argv[2]); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment