Logo Search packages:      
Sourcecode: qarecord version File versions  Download package

diskwrite.cpp

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <qfile.h>
#include <qfileinfo.h>

#include "diskwrite.h"

#define WAVBUFSIZE               32768


DiskWrite::DiskWrite(SettingsData *settings, RingBuffer *p_ringBuffer) 
{
    wavdata = (unsigned char *)malloc(WAVBUFSIZE);
    ringBuffer = p_ringBuffer;
    rate = settings->getRate();
    channels = settings->getChannels();
    samplesize = settings->getSampleSize();
    framesize = channels * samplesize;
    sizeLimit = 1048576 * settings->getSplitMB();

    isPaused = false;
}

void DiskWrite::finishFile()
{
    fseek(wavfile, 4, SEEK_SET); // Fill in ChunkSize
    writeLong(currentDataSize + (extendedHeader ? 36+24 : 36));
    // Fill in Subchunk2Size
    fseek(wavfile, (extendedHeader ? 40+24 : 40), SEEK_SET);
    writeLong(currentDataSize);
    fseek(wavfile, 0, SEEK_END);
    fclose(wavfile);
}

static QString insertExtension(QString fname, QString ext)
{
    QFileInfo f(fname);
    if (f.suffix().isEmpty()) { 
        return fname + ext;
    }
    return f.path() + '/' + f.completeBaseName() + ext + '.' + f.suffix(); 
}

void DiskWrite::startFile()
{
    renameExistingFile();
    qWarning("Writing to file %s", qPrintable(currentFileName));

    if (!(wavfile = fopen(currentFileName.toLatin1(), "w"))) {
        doRecord = false;
        qWarning("File open error");
        return;
    }

    extendedHeader = channels > 2 || samplesize > 2;
    currentDataSize = 0;
    write4CC("RIFF");
    writeLong(0x0); // ChunkSize, leave empty for now
    write4CC("WAVE");
    write4CC("fmt ");
    writeLong(extendedHeader ? 40 : 16); // Subchunk1Size
    writeShort(extendedHeader ? 0xFFFE : 1); // wFormatTag
    writeShort(channels); // nChannels
    writeLong(rate); // SampleRate
    writeLong(rate * framesize); // ByteRate
    writeShort(framesize); // BlockAlign
    writeShort(8 * samplesize); // BitsPerSample
    if (extendedHeader) { // WAVE_FORMAT_EXTENSIBLE
        writeShort(22);
        writeShort(8 * samplesize); // ValidBitsPerSample
        writeLong(0); // Channel mask
        // GUID
        fwrite("\x01\x00\x00\x00\x00\x00\x10\x00\x80\x00\x00\xAA\x00\x38\x9B\x71", 
            16, 1, wavfile);
    }
    write4CC("data");
    writeLong(0); // Subchunk2Size
}


void DiskWrite::renameExistingFile()
{
    int i=0;
    QFile file(currentFileName);
    while (file.exists()) {
        i++;
        file.setFileName(insertExtension(currentFileName, ".old" + QString("%1").arg(i)));
    }
    if (i > 0) {
        QString temp = file.fileName();
        qWarning("%s already exists, renaming old file to %s", 
            currentFileName.toUtf8().constData(), temp.toUtf8().constData());
        file.setFileName(currentFileName);
        file.rename(temp);
    }
}


DiskWrite::~DiskWrite(){
    /* Wait for thread to finish */
    doRecord = false;
    wait();
    free(wavdata);
}

int DiskWrite::readBlock(bool waitIfEmpty, bool writeToFile)
{
    long startpos, count;
    unsigned char * ringBuf;
    bool split = false;

    ringBuf = ringBuffer->beginRead(startpos, count, waitIfEmpty);
    if (count == 0) {
        return 0;
    }

    if (writeToFile) {
        if (count > WAVBUFSIZE) {
            count = WAVBUFSIZE;
        }

        if (currentDataSize + count > sizeLimit) {
            count = sizeLimit - currentDataSize;
            split = true;
        }
        if (count % framesize != 0) {
            /* Always write a proper frame */
            count -= count % framesize;
        }

        if (wavfile && (fwrite(&ringBuf[startpos], count, 1, wavfile) != 1)) {
            qWarning("File write error");
        }
        currentDataSize += count;
        totalDataSize += count;
        if (split) {
            finishFile();
            currentFileName = insertExtension(baseFileName, ".part" + 
                QString("%1").arg(++fileIndex));
            startFile();
        }
    }
    ringBuffer->endRead(startpos+count);
    return count;
}

void DiskWrite::run() 
{
    doRecord = true;
    currentFileName = baseFileName;
    totalDataSize = 0;
    fileIndex = 1;
    startFile();
    ringBuffer->discardBuffer();
    while(doRecord) {
        readBlock(true, !isPaused);
    }
    // Keep writing blocks until buffer is empty
    while (!isPaused && (readBlock(false, true) > 0)) {} 

    finishFile();
}


void DiskWrite::writeLong(unsigned long i)
{
    unsigned char outbuf[4];
    outbuf[3] = i >> 24;
    outbuf[2] = (i >> 16) & 0xFF;
    outbuf[1] = (i >> 8) & 0xFF; 
    outbuf[0] = i & 0xFF;
    if (wavfile && (fwrite(outbuf, 4, 1, wavfile) != 1)) {
        qWarning("File write error\n");
    }
}

void DiskWrite::writeShort(short i)
{
    unsigned char outbuf[2];
    outbuf[1] = (i >> 8) & 0xFF;
    outbuf[0] = i & 0xFF;
    if (wavfile && (fwrite(outbuf, 2, 1, wavfile) != 1)) {
        qWarning("File write error\n");
    }
}

void DiskWrite::write4CC(const char *c)
{
    if (wavfile && (fwrite(c, 4, 1, wavfile) != 1)) {
        qWarning("File write error\n");
    }
}

Generated by  Doxygen 1.6.0   Back to index