August 20, 2014

I Have Done Something No One Else Has!

     As you probably know a lot of news articles tend to use over exaggerated titles to gain attention, and the title of this post is almost no different. I say almost because this post is meant to share long sought after information instead of generating views. PS I bet someone has done this before, but I might be the first to openly post it to the web.

So what did I do?

     I have been looking to be able to use Java to record/capture the audio output by the OS for awhile now. It is a concept which sounds straight forward, should be straight forward, but is not straight forward. In my research I have found forum posts from as far back as 2011 of people looking for how to go about this with native Java code and all posts I have found are still without an explicit solution.

Setup Instructions and What I Learned:

     To get this code to work (on Windows 7) I had to open the sound options menu (Start Menu → search for 'Sound') and after opening the Sound configuration window select the 'Recording' tab then right click in the white space and select both 'Show Disabled Devices' and 'Show Disconnected Devices'. This caused 'Stereo Mix' to appear (grayed out) as a recording device and to enable it right click and selected 'Enable'.

Important Note: 
     As you can see from my code and from what my research has shown me, when recording audio with native Java there is NO WAY TO SELECT A DIFFERENT INPUT, that is, you can only grab/record/capture the OS's default device. This makes no sense to me, but in all the example code I have looked at to capture audio from a device I have seen NO WAY to select a secondary or tertiary device.

     Knowing this, I had to then set the 'Stereo Mix' in the Sound configuration window as the default recording device by right clicking it and selecting 'Set as Default'. This will allow you to record the audio output by your OS, HOWEVER YOU NEED TO KNOW this will very likely stop your microphone from working with all applications (even if the program is set to use a specific device, as opposed to the OS default device). If this is a problem (if you use Skype, Teamspeak 3, Mumble, or some other VOIP program) you can circumvent this by right clicking on the microphone in the recording tab and select 'Set as Default Communications Device'. Configuring the devices in this way has allowed me to still use VOIP programs and record the audio from the Stereo Mix.

Finally The Code: 
/*
 * This program records audio from a microphone for a period of X seconds specified by the user and saves it to a Record.wav file.
 * This code maybe freely used for any and all purposes (Reginald Aryee).
 * 
 * Parts of this code I got form: http://www.youtube.com/watch?v=GVtl19L9GxU&list=UUaKrpNOAP7pmHk4XyCY_AuQ&index=4
 * The rest of the code is from myself Reginald Aryee.
 */

import java.io.*;
import java.util.Scanner;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

public class Recorder 
{
 
 public static void main(String[] args)
 {
  System.out.println("Program started. ");
  System.out.println("How many seconds would you like the recording to last?  ");
  
  Scanner scan = new Scanner(System.in);
  int UserInput = scan.nextInt();     // String s = scan.next();   // User input to find out how long to record for.
  scan.close();
  
  try
  {
   AudioFormat format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, 44100, 16, 2, 4, 44100, false);  //Defining the properties of the .WAV file
            // 44,100hz sample rate, 16 bit sample size, 2 audio channels (stereo), frame size?, big-endian or little-endian)
   
   DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);  // Specifying the format to put the audio in.
   System.out.println(info);    // Extra info
   
   if(!AudioSystem.isLineSupported(info)) 
   { 
    System.err.println("Line not supported"); 
   }
   
   final TargetDataLine targetLine = (TargetDataLine)AudioSystem.getLine(info);   // Looks at the default audio recording device.
   System.out.println((TargetDataLine)AudioSystem.getLine(info));  // Extra info
   targetLine.open(); // The program can now have access to the live audio feed.
   
   System.out.println("Starting Recording... ");
   targetLine.start();  // Starts listening to the device.
   Thread thread = new Thread()
   {
    @Override public void run()
    {
     AudioInputStream audioStream =  new AudioInputStream(targetLine);  // Data Stream
     System.out.println("AudioInputStream(targetLine) = " + audioStream); // Extra info
     System.out.println("targetLine = " + targetLine);                    // Extra info

     File audioFile = new File("Record.wav");
     try // When data is coming through the data line/stream...
     {
      AudioSystem.write(audioStream, AudioFileFormat.Type.WAVE, audioFile); // Recording the audio to a file.
     }
     catch(IOException ioe) {ioe.printStackTrace();}
     System.out.println("Stopped Recording");
    }
   };
   
   thread.start();
   Thread.sleep(UserInput * 1000); // Main Thread sleeps to allow the recording to finish, otherwise it would cut off the recording.
   targetLine.stop();  // Stops the data flow from the device.
   targetLine.close(); // Release the resource
   System.out.println("Program ended.");
  }
  catch(LineUnavailableException lue) { lue.printStackTrace(); }
  catch(InterruptedException ie) {ie.printStackTrace();}
 }
}

(Because this appears to be a long unanswered question I am tagging this to hell.)

Tags: record PC audio output, capture PC audio output, record audio output, capture audio output, Java audio, Java audio capture, Java audio record, Java audio output) 

No comments:

Post a Comment