Saving AudioSample as a sound file of any format

please format code with </> button * homework policy * asking questions

Hello,

I am using the sound library to generate sound from existing .wav files. And after looking for a while for a way to save the generated sound to a file, I haven’t found any (simple) solution. It just surprises me that a library such as .sound that enables you to open and manipuate sound files so easily, does not include a save or export function. Am I missing something here? Is it that hard to create sound files?

Thanks for the help!

See previous forum post

1 Like

Thanks for the answer paulgoux.

I knew about minim and Audiorecorder, but it seems like it forces me to actually play the sound to record it which will take a lot of time. This is a problem because i am trying to take a few sound files and turn it into a new file that has the individual sounds with some time between. Since I need to do this thousands of times, having to play the sound before turning it into a file is not ideal. So I was hoping to find a way around it.

If I’m wrong about having to play a sound to record it, or if you know of a different solution please let me know.
Thanks!

Honestly not sure this isn’t a topic I’ve researched in depth just some quick googling however I have worked with fft analysis before to convert an audio file to a spectrogram and I had the same issue, analysis was only available during playback and resolution would be dependant on playback speed. This was using processing sound as opposed to minim, so I think it might be a processing limitation perhaps someone with more knowledge can enlighten us.

Thanks for trying anyway! I guess the code will just have to run for hours haha

i’m also looking for a way to save data directly to sound files.

found this post: https://forum.processing.org/two/discussion/4339/how-to-save-a-wav-file-using-audiosystem-and-audioinputstream-of-javasound

it uses byte array but only creates 8 bit wav files. any suggestions how the code could be modified to save 16 bit sound?

2 Likes

Hey! That post fixed my issue! Thanks!
In my case, quaity isn’t a big deal, so i won’t be trying to figure out the 16bit solution. But if you figure it out, please let me know

I have made changes to be able to generate a 16 bit wav file from a string containing a sequence of float values generated from a mono sound file.

import processing.sound.*;
import javax.sound.sampled.*;
import java.io.*;

processing.sound.AudioSample file;
float[] floatArray;
String[] txt;
byte[] pcm_data;

void setup(){
  // Load string containing float values
  txt = loadStrings("str.txt");
  
  // Create array to transform String to float
  floatArray = new float[txt.length];
  
  // Create pcm array for storing 16 bits values representing the floats
  // 16 bits = 2 bytes, also mono = 1 byte so 2 * 1 * txt.length
  pcm_data= new byte[2 * txt.length];
  
  for(int i = 0; i < txt.length; i++){
    // String to float
    floatArray[i] = float(txt[i]);
    // Convert float32 to 16 bit integer, values between -32768 and 32767 (since -1 < floatArray[i] < 1)
    int aux = floor(32767 * floatArray[i]);
    // 16 bits per iteration, so I need to generate and fill 2 separate bytes per iterarion
    // Convert first 8 bits (+ significant) of the 16 bit int to a byte
    pcm_data[i * 2] = byte(aux); 
    // Convert last 8 bits (- significant) of the 16 bit int to a byte
    pcm_data[(i* 2) + 1] = (byte)((int) aux >> 8);
  }
  
  // Preparing the save PCM ----------------------------
  // Define the AudioFormat to save
  AudioFormat frmt = new AudioFormat(44100, 16, 1, true, false); // Samplerate, Samplesize em Bits, channels, signed, bigendian
  // Buffer for recording the audio
  AudioInputStream ais = new AudioInputStream( 
    new ByteArrayInputStream(pcm_data), 
    frmt, 
    pcm_data.length / frmt.getFrameSize()
  );
  
  // Try to save the file in the current directory
  try {
    AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new
      File(dataPath("") + "audio.wav")
    );
  } 
  catch(Exception e) {
    e.printStackTrace();
  }
  
  noLoop();
}

void draw(){

}

I have a slightly different bur related problem: I would like to record to disk the sound produced by several sound files. Actually, I’m speaking about a simple sequencer using 4 mono wav samples. With the Sound library, I can control the sound generation. However, I can´t record the output to disk.
I understand that this last program can record audio to disk, but the data is being read from a sequence of float values in a text file, not from a SoundFile object (or from a wav file).
Does anybody know of any way to do what I need?

I found this topic while working with minim and looking for how to save an array of floats as an audio file. The solution has been found, of course, but this may be of interest:

/**
    * Saves audio data to 16-bit integer PCM format, which Processing can also open.
    * 
    * @param samples			an array of floats in the audio range (-1.0f, 1.0f)
    * @param sampleRate		audio sample rate for the file
    * @param fileName			name of the file to save to
    * @throws IOException		an Exception you'll need to handle to call this method
    * @throws UnsupportedAudioFileException		another Exception
    */
public static void saveAudioToFile(float[] samples, float sampleRate, String fileName)
        throws IOException, UnsupportedAudioFileException {
    // Convert samples from float to 16-bit PCM
    byte[] audioBytes = new byte[samples.length * 2];
    int index = 0;
    for (float sample : samples) {
        // Scale sample to 16-bit signed integer
        int intSample = (int) (sample * 32767);
        // Convert to bytes
        audioBytes[index++] = (byte) (intSample & 0xFF);
        audioBytes[index++] = (byte) ((intSample >> 8) & 0xFF);
    }
    // Create an AudioInputStream
    ByteArrayInputStream byteStream = new ByteArrayInputStream(audioBytes);
    AudioFormat format = new AudioFormat(sampleRate, 16, 1, true, false);
    AudioInputStream audioInputStream = new AudioInputStream(byteStream, format, samples.length);
    // Save the AudioInputStream to a WAV file
    File outFile = new File(fileName);
    AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, outFile);
}

/**
    * Saves audio data to a 32-bit floating point format that has higher resolution than 16-bit integer PCM. 
    * The format can't be opened by Processing but can be opened by audio applications. 
    * 
    * @param samples			an array of floats in the audio range (-1.0f, 1.0f)
    * @param sampleRate		the sample rate for the file
    * @param fileName			name of the file
    * @throws IOException		an Exception you'll need to catch to call this method (see keyPressed entry for 's')
    */
public static void saveAudioTo32BitPCMFile(float[] samples, float sampleRate, String fileName) throws IOException {
    // convert samples to 32-bit PCM float
    byte[] audioBytes = new byte[samples.length * 4];
    int index = 0;
    // convert to IEEE 754 floating-point "single format" bit layout 
    for (float sample : samples) {
        int intBits = Float.floatToIntBits(sample);
        audioBytes[index++] = (byte) (intBits & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 8) & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 16) & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 24) & 0xFF);
    }
    ByteArrayInputStream byteStream = new ByteArrayInputStream(audioBytes);
    AudioFormat format = new AudioFormat(sampleRate, 32, 1, true, false);
    AudioInputStream audioInputStream = new AudioInputStream(byteStream, format, samples.length);
    File outFile = new File(fileName);
    AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, outFile);      
}

/**
    * Saves stereo audio data to 16-bit integer PCM format, which Processing can also open.
    * 
    * @param leftChannel		an array of floats in the audio range (-1.0f, 1.0f)
    * @param rightChannel		an array of floats in the audio range (-1.0f, 1.0f)
    * @param sampleRate		audio sample rate for the file
    * @param fileName			name of the file to save to
    * @throws IOException		an Exception you'll need to handle to call this method (see keyPressed entry for 's')
    * @throws UnsupportedAudioFileException		another Exception (see keyPressed entry for 's')
    */
public static void saveStereoAudioToFile(float[] leftChannel, float[] rightChannel, float sampleRate, String fileName)
        throws IOException, UnsupportedAudioFileException {
    int numSamples = leftChannel.length;
    // Convert samples from float to 16-bit PCM
    byte[] audioBytes = new byte[leftChannel.length * 2 * 2];
    int index = 0;
    for (int i = 0; i < numSamples; i++) {
        // Scale leftChannel sample to 16-bit signed integer
        int intSample = (int) (leftChannel[i] * 32767);
        // Convert to bytes
        audioBytes[index++] = (byte) (intSample & 0xFF);
        audioBytes[index++] = (byte) ((intSample >> 8) & 0xFF);
        // Scale rightChannel sample to 16-bit signed integer
        intSample = (int) (rightChannel[i] * 32767);
        // Convert to bytes
        audioBytes[index++] = (byte) (intSample & 0xFF);
        audioBytes[index++] = (byte) ((intSample >> 8) & 0xFF);
        
    }
    // Create an AudioInputStream
    ByteArrayInputStream byteStream = new ByteArrayInputStream(audioBytes);
    AudioFormat format = new AudioFormat(sampleRate, 16, 1, true, false);
    AudioInputStream audioInputStream = new AudioInputStream(byteStream, format, numSamples);
    // Save the AudioInputStream to a WAV file
    File outFile = new File(fileName);
    AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, outFile);
}

/**
    * Saves stereo audio data to a 32-bit floating point format that has higher resolution than 16-bit integer PCM. 
    * The format can't be opened by Processing but can be opened by audio applications. 
    * 
    * @param leftChannel		an array of floats in the audio range (-1.0f, 1.0f)
    * @param rightChannel		an array of floats in the audio range (-1.0f, 1.0f)
    * @param sampleRate		the sample rate for the file
    * @param fileName			name of the file
    * @throws IOException		an Exception you'll need to handle when calling this method
    */
public static void saveStereoAudioTo32BitPCMFile(float[] leftChannel, float[] rightChannel, float sampleRate, String fileName) throws IOException {
    int numSamples = leftChannel.length;
    // convert leftChannel to 32-bit PCM float
    byte[] audioBytes = new byte[numSamples * 2 * 4];
    int index = 0;
    // convert to IEEE 754 floating-point "single format" bit layout 
    for (int i = 0; i < numSamples; i++) {
        // Left channel sample
        int intBits = Float.floatToIntBits(leftChannel[i]);
        audioBytes[index++] = (byte) (intBits & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 8) & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 16) & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 24) & 0xFF);
        // Right channel sample
        intBits = Float.floatToIntBits(rightChannel[i]);
        audioBytes[index++] = (byte) (intBits & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 8) & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 16) & 0xFF);
        audioBytes[index++] = (byte) ((intBits >> 24) & 0xFF);
    }
    // create an AudioInputStream
    ByteArrayInputStream byteStream = new ByteArrayInputStream(audioBytes);
    AudioFormat format = new AudioFormat(sampleRate, 32, 2, true, false);
    AudioInputStream audioInputStream = new AudioInputStream(byteStream, format, numSamples);
    // write the file 
    File outFile = new File(fileName);
    AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, outFile);      
}

I’ve incorporated this into a library I am developing in Eclipse – that’s the reason for the static keyword and the ‘f’ after floating point numbers. A typical way to call it from a keyPressed event switch statement would be like this:

case 's': 
  try {
    saveAudioToFile(audioSignal, sampleRate, sketchPath("") + "/wavesynth.wav");
    println("Saved file to sketch path: "+ sketchPath(""));
  }
  catch (IOException e) {
    println("--->> There was an error outputting the audio file wavesynth.wav."+ e.getMessage());
  }
  catch (UnsupportedAudioFileException e) {
    println("--->> The file format is unsupported."+ e.getMessage());
  }

And don’t forget:

import java.io.*;
import javax.sound.*;