Sophie

Sophie

distrib > Fedora > 15 > i386 > by-pkgid > 66e30aac992ff3843dd8ab4b0e9392b6 > files > 14

libofa-devel-0.9.3-17.fc15.i686.rpm

/* ------------------------------------------------------------------

   libofa -- the Open Fingerprint Architecture library

   Public Domain (PD) 2006 MusicIP Corporation
   No rights reserved.

-------------------------------------------------------------------*/
#include "protocol.h"
#ifdef WIN32
#include "io.h"
#endif
#include <fcntl.h>

static bool readBytes(int fd, unsigned char *buf, int size) {
    int ct = 0;
    while (ct < size) {
	unsigned char tmp[4096];

	int x = size - ct;
	if (x > 4096)
	    x = 4096;

	int n = read(fd, tmp, x);

	if (n <= 0) {
	    return false;
	}

	for (int i = 0; i < n; ++i) {
	    buf[ct + i] = tmp[i];
	}
	ct += n;
    }
    return true;
}

// This method only supports PCM/uncompressed format, with a single fmt
// chunk followed by a single data chunk
AudioData* loadWaveFile(char *file) {

    int srate = 0;
    int channels = 0;

    int fd = open(file, O_RDONLY | 0x8000);
    if (fd == -1)
	return 0;

    if (lseek(fd, 0L, SEEK_SET) == -1L) {
	close(fd);
	return 0;
    }

    unsigned char hdr[36];
    if (!readBytes(fd, hdr, 36)) {
	close(fd);
	return 0;
    }
    if (hdr[0] != 'R' || hdr[1] != 'I' || hdr[2] != 'F' || hdr[3] != 'F') {
	close(fd);
	return 0;
    }
    // Note: bytes 4 thru 7 contain the file size - 8 bytes
    if (hdr[8] != 'W' || hdr[9] != 'A' || hdr[10] != 'V' || hdr[11] != 'E') {
	close(fd);
	return 0;
    }
    if (hdr[12] != 'f' || hdr[13] != 'm' || hdr[14] != 't' || hdr[15] != ' ') {
	close(fd);
	return 0;
    }

    long extraBytes = hdr[16] + (hdr[17] << 8) + (hdr[18] << 16) + (hdr[19] << 24) - 16;
    int compression = hdr[20] + (hdr[21] << 8);
    // Type 1 is PCM/Uncompressed
    if (compression != 1) {
	close(fd);
	return 0;
    }
    channels = hdr[22] + (hdr[23] << 8);
    // Only mono or stereo PCM is supported in this example
    if (channels < 1 || channels > 2) {
	close(fd);
	return 0;
    }
    // Samples per second, independent of number of channels
    srate = hdr[24] + (hdr[25] << 8) + (hdr[26] << 16) + (hdr[27] << 24);
    // Bytes 28-31 contain the "average bytes per second", unneeded here
    // Bytes 32-33 contain the number of bytes per sample (includes channels)
    // Bytes 34-35 contain the number of bits per single sample
    int bits = hdr[34] + (hdr[35] << 8);
    // Supporting othe sample depths will require conversion
    if (bits != 16) {
	close(fd);
	return 0;
    }

    // Skip past extra bytes, if any
    if (lseek(fd, 36L + extraBytes, SEEK_SET) == -1L) {
	close(fd);
	return 0;
    }

    // Start reading the next frame.  Only supported frame is the data block
    unsigned char b[8];
    if (!readBytes(fd, b, 8)) {
	close(fd);
	return 0;
    }
    // Do we have a fact block?
    if (b[0] == 'f' && b[1] == 'a' && b[2] == 'c' && b[3] == 't') {
	// Skip the fact block
	if (lseek(fd, 36L + extraBytes + 12L, SEEK_SET) == -1L) {
	    close(fd);
	    return 0;
	}
	// Read the next frame
	if (!readBytes(fd, b, 8)) {
	    close(fd);
	    return 0;
	}
    }

    // Now look for the data block
    if (b[0] != 'd' || b[1] != 'a' || b[2] != 't' || b[3] != 'a') {
	close(fd);
	return 0;
    }
    long bytes = b[4] + (b[5] << 8) + (b[6] << 16) + (b[7] << 24);

    long ms = (bytes/2)/(srate/1000);
    if ( channels == 2 ) ms /= 2;

    // No need to read the whole file, just the first 135 seconds
    int sampleSize = 135;
    long bytesInNSecs = sampleSize * srate * 2 * channels;
    bytes = bytes > bytesInNSecs ? bytesInNSecs : bytes;

    unsigned char *samples = new unsigned char[bytes];
    if (!readBytes(fd, samples, bytes)) {
	delete[] samples;
	close(fd);
	return 0;
    }
    close(fd);

    AudioData *data = new AudioData();
    data->setData(samples, OFA_LITTLE_ENDIAN, bytes/2, srate,
	    channels == 2 ? 1 : 0, ms, "wav");
    return data;
}