如何填充wavfile的“数据字段”

时间:2017-01-11 12:36:10

标签: c++ c wav

嗨我正试图从一块棋盘上录制,我已经成功录制了4秒。问题是当我尝试记录更多时间时,我得到一个错误告诉我没有足够的内存。我的目标是记录一个5分钟的文件。到目前为止,我已经创建了一个名为snIn [256]的缓冲区,其中包含样本。我将它发送到[16K * 4sec]的大缓冲区,当它已满时,我创建了wav文件。

#include "SAI_InOut.hpp"
#include "F746_GUI.hpp"
#include "Delay.hpp"
#include "WaveformDisplay.hpp"
#include "SDFileSystem.h"
#include "wavfile.h"
using namespace Mikami;

#define RES_STR_SIZE 0x20
#define WAVFILE_SAMPLES_PER_SECOND 16000
#define REC_TIME 4

  //Create an SDFileSystem object
 SDFileSystem sd("sd");

bool flag = 1;
int count = 0;
char *res_buf; 
int rp = 0;
const int NUM_SAMPLES = WAVFILE_SAMPLES_PER_SECOND * REC_TIME;
Array<int16_t> my_buffer(NUM_SAMPLES);
int j = 0;
static const char *target_filename = "/sd/rectest.wav";     
const int SEG_SIZE = 256;
int sent_array = 0;


int rec(const char *filename, Array<int16_t> my_buffer)
{   
    j = 0;
    flag = 0;
    sent_array = 0;

    WavFileResult result;
    wavfile_info_t info;
    wavfile_data_t data;

    WAVFILE_INFO_AUDIO_FORMAT(&info)    = 1;
    WAVFILE_INFO_NUM_CHANNELS(&info)    = 1;
    WAVFILE_INFO_SAMPLE_RATE(&info)     = WAVFILE_SAMPLES_PER_SECOND;
    WAVFILE_INFO_BITS_PER_SAMPLE(&info) = 16;
    WAVFILE_INFO_BYTE_RATE(&info)       = WAVFILE_INFO_NUM_CHANNELS(&info) * WAVFILE_INFO_SAMPLE_RATE(&info) * (WAVFILE_INFO_BITS_PER_SAMPLE(&info) / 8);
    WAVFILE_INFO_BLOCK_ALIGN(&info)     = 2;


    WAVFILE *wf = wavfile_open(filename, WavFileModeWrite, &result);
    if (result != WavFileResultOK) {
        wavfile_result_string(result, res_buf, RES_STR_SIZE);
        printf("%s", res_buf);
        return result; 
    } else printf ("Open file success \r\n");

    rp = 0;
    WAVFILE_DATA_NUM_CHANNELS(&data) = 1;

         result = wavfile_write_info(wf, &info);
        if (result != WavFileResultOK) {
            wavfile_result_string(result, res_buf, RES_STR_SIZE);
            printf("%s", res_buf);
            return result; } else printf ("Write info success \r\n");

    while ( rp < NUM_SAMPLES ) {
        WAVFILE_DATA_CHANNEL_DATA(&data, 0) = my_buffer[rp];       
        result = wavfile_write_data(wf, &data);
        rp += 1;
    }

    if (result != WavFileResultOK) {
        wavfile_result_string(result, res_buf, RES_STR_SIZE);
        printf("%s", res_buf);
        return result; }  else printf ("Write Data file success \r\n");

    result = wavfile_close(wf);
    if (result != WavFileResultOK) {
        wavfile_result_string(result, res_buf , RES_STR_SIZE);
        printf("%s", res_buf);
        return result; }  else printf ("Close file success \r\n");

    //UnMount the filesystem
    sd.unmount();

    printf("Success rec !\r\n");
    return 0;
}


int main()
{
    //Mount the filesystem
      sd.mount();

    const float MAX_DELAY = 0.5f;       // 最大遅延,単位:秒
    const int FS = I2S_AUDIOFREQ_16K;   // 標本化周波数: 16 kHz
    const uint32_t MAX_ARRAY_SIZE = (uint32_t)(MAX_DELAY*FS);
    SaiIO mySai(SaiIO::BOTH, 256, FS, INPUT_DEVICE_DIGITAL_MICROPHONE_2);
    Label myLabel(185, 10, "Delay System", Label::CENTER, Font16);
    // ButtonGroup: "ON", "OFF"
    const uint16_t BG_LEFT = 370;
    const uint16_t BG_WIDTH = 100;
    const uint16_t BG_HEIGHT = 45;
    ButtonGroup onOff(BG_LEFT, 40, BG_WIDTH/2, BG_HEIGHT,
                      2, (string[]){"ON", "OFF"}, 0, 0, 2, 1);
    const uint16_t SB_LEFT = BG_LEFT - 320;
    const uint16_t SB_WIDTH = 270;
    const uint16_t SB_Y0 = 240;
    char str[20];
    sprintf(str, "    %3.1f [s]", MAX_DELAY);
    SeekBar barDelay(SB_LEFT, SB_Y0, SB_WIDTH,
                     0, MAX_ARRAY_SIZE, 0, "0", "", str);
    NumericLabel<float> labelDelay(SB_LEFT+SB_WIDTH/2, SB_Y0-40, "DELEY: %4.2f", 0, Label::CENTER);
    DelaySystem delaySystem(MAX_ARRAY_SIZE);
    WaveformDisplay displayIn(*GuiBase::GetLcdPtr(), SB_LEFT+7, 70, 256, 9,LCD_COLOR_WHITE, LCD_COLOR_CYAN,GuiBase::ENUM_BACK);
    Label inLabel(SB_LEFT-30, 65, "IN");
    WaveformDisplay displayOut(*GuiBase::GetLcdPtr(), SB_LEFT+7, 130, 256, 9,LCD_COLOR_WHITE, LCD_COLOR_CYAN,GuiBase::ENUM_BACK);
    Label outLabel(SB_LEFT-30, 125, "OUT");

    int runStop = 1;
    Array<int16_t> snIn(mySai.GetLength());
    Array<int16_t> snOut(mySai.GetLength());

    mySai.RecordIn();
    mySai.PlayOut();
    mySai.PauseOut();


    while (true)
    {
        // On/OFF
        int num;
        if (onOff.GetTouchedNumber(num))
            if (runStop != num)
            {
                if (num == 0) mySai.ResumeOut();
                else          mySai.PauseOut();
                runStop = num;
            }

        if (mySai.IsCompleted())
        {
            for (int n=0; n<mySai.GetLength() ; n++)
            {
                int16_t xL, xR;
                mySai.Input(xL,xR);
                int16_t xn = xL + xR;
                snIn[n] = xn;
                my_buffer[j] = xn;
                j++;
                if (j == NUM_SAMPLES && flag == 1) {
                    rec (target_filename , my_buffer); } 

                int16_t yn = delaySystem.Execute(xn);
                mySai.Output(yn, yn);
                snOut[n] = yn;  
            }

            mySai.Reset();     
            displayIn.Execute(snIn);  

        }     
    }
}

我想到了一个可能的解决方案,一次又一次地用snIn [256]缓冲区(而不是使用my_buffer)直接填充wavefile的“数据字段”,最后关闭wavfile。请让我知道您对此以及其他解决方案的看法

1 个答案:

答案 0 :(得分:0)

需要注意的事项:1)在执行写入操作时,仍会有更多数据进入。

至少我会对这些数据进行双重缓冲,因此可以写入一个缓冲区,而另一个填充缓冲区。

通常这意味着使用中断来收集样本(当前正在向其中提交缓冲区。)

前台程序等待当前缓冲区“满”,然后启动写操作。

然后再次等待缓冲区满#39;

中断函数跟踪正在填充的缓冲区和当前索引到该缓冲区。当缓冲区已满时,设置一个全局的&#39;状态让前台程序知道哪个缓冲区已准备好写入。

前台程序写入缓冲区,然后重置该缓冲区的状态。