Search code examples
audioffmpegesp32

What ffmpeg command to use to convert a list of unsigned integers into an audio file?


I have a file that contains a list of about forty thousand integers that are space delimited, with each integer between the value of 0 and 255. It is this file here:

https://github.com/johnlai2004/sound-project/blob/master/integers.txt

If you connect a speaker to an ESP32 breakout board, then run this list of integers through the digital to analog converter at a frequency of 24kHz, you will hear the sentence, "That's not the post that you missed."

What I want to know is how do you use FFMPEG to convert this list of integers into a sound file that other computer can play to hear the same phrase? I tried this command:

ffmpeg -f u8 -ac 1 -ar 24000 -i integers.txt -y audio.wav

But my audio.wav just sounds like white noise. I tried a few other values for -f and for -ar, but all I hear are different frequencies of white noise and maybe some extra buzzing.

Is it possible to use ffmpeg to translate my list of integers into an audio file for other computers to play? If so, what's the correct ffmpeg command to do this?

OTHER NOTES

If it helps, this is the sketch file that I upload to an ESP32 if I want to hear the audio:

https://github.com/johnlai2004/sound-project/blob/master/play-audio.ino

In short, the file looks like this:

#define speakerPin 25                          //The pins to output audio on. (9,10 on UNO,Nano)
#define bufferTotal 1347
#define buffSize 32

byte buffer[bufferTotal][buffSize];
int buffItemN = 0;
int bufferN = 0;

hw_timer_t * timer = NULL;
portMUX_TYPE timerMux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR onTimer() {
  portENTER_CRITICAL_ISR(&timerMux);


  byte v = buffer[bufferN][buffItemN];
  dacWrite(speakerPin,v);

  buffItemN++;

  if(buffItemN >= buffSize){                                      //If the buffer is empty, do the following
    buffItemN = 0;                                              //Reset the sample count
    bufferN++;
    if(bufferN >= bufferTotal)
      bufferN = 0;
  }

  portEXIT_CRITICAL_ISR(&timerMux);

}

void setup() {      

/* buffer records */
buffer[0][0]=88;  // I split the long list of integers and load it into a 2D array
buffer[0][1]=88;
buffer[0][2]=86;
buffer[0][3]=85;
//etc....
buffer[1346][28]=94;
buffer[1346][29]=92;
buffer[1346][30]=92;
buffer[1346][31]=95;


/* end buffer records */

  timer = timerBegin(0, 80, true);
  timerAttachInterrupt(timer, &onTimer, true);
  timerAlarmWrite(timer, 41, true);
  timerAlarmEnable(timer);

}

void loop() {

}

The buffer... is the list of integers found in the integers.txt file.


Solution

  • As @Gyan suggested in comments, I had to convert my list of integers to a binary file first before running the ffmpeg command. So I created a golang script called main.go with this:

    package main
    
    import (
      "io/ioutil"
      "strings"
      "strconv"
      "os"
    )
    func main() {
    
      input:="./integers.txt"
      output:="./binary.raw"
    
      // Load the list of integers into memory
      contentbyte, _ := ioutil.ReadFile(input)
      content := strings.Split(string(contentbyte)," ");
    
      // Prepare to output a new binary file
      f, err := os.OpenFile(output, os.O_APPEND|os.O_WRONLY|os.O_CREATE, 0600)
      if err != nil {
          panic(err)
      }
      defer f.Close()
    
      for _,val := range content {
        // Convert each integer to a binary value and write to output file
        i,_ := strconv.Atoi(val)
        if _, err = f.Write([]byte{byte(i)}); err != nil {
            panic(err)
        }
      }
    
    }
    

    I run the go run main.go to give me the binary.raw file. I then ran the ffmpeg command as posted in my question like this ffmpeg -f u8 -ar 24000 -ac 1 -i binary.raw -y audio.wav.

    The audio.wav file sounds just like the output of my ESP32 + speaker, which is what I wanted.