August 20, 2014

The Podside Project: Extras

     As always, when I code or think of software design I come up with interesting ideas which could be implemented as part of the project to add more features, quality of life changes, performance enhancements, and overall value of the software. 

For this project I thought of:
  • Adaptive/Smart MP3 file saving
  • Podcast XML file updater
  • iOS/Android/Windows App (custom or generic apps)
  • Push notifications
    • Live in 5
    • We Are Live!
    • Broadcast finished, check iTunes soonTM
Smart Saving:
     There is an issue which occurs every once in a while where a podcaster is recording an episode and then all of a sudden their recording program or computer crashes which usually results in the recording being completely lost or corrupted. The idea of a Smart Saving feature is the program will store/cache the audio in memory and can save the file every X minutes to the hard drive. 
     This can be implemented in one of 2 ways. (1) X minutes of audio is stored in a large buffer until X time passes and then the audio from the buffer is saved to a file with more audio added to the file every X minutes. (2) All audio is saved to the hard drive in X minute segments (AudioFile1.mp3, AudioFile2.mp3, etc) and then once the recoding is stopped the program then writes a the audio segments to the one file (Podcast Episode #.mp3).

(1) Pros: This allows for the file to be written in the background when the recording is still going on and so there is minimal interruption. If a crash occurs less than X minutes of audio will be lost.
Cons: This can still be susceptible to file corruption if the program or computer crashes during the writing/saving of the audio once the X minutes fills the buffer. However, this is still significantly better than continually writing data to a file in real-time.
2) Pros: This allows for the entire recording process to be completed before the audio is combined. If there is some form of crash during the recording only X minutes or less would be lost.
When combining the audio files together it can be done in such a way that all the different audio segments will remain intact until all the audio is combined and saved to the new file. This guarantees the process will complete successfully (ideally anyway).

Cons: This method requires the recording process to be completely finished and then it can combine the audio files together, thus resulting in additional time to the process.

Podcast XML Updater:
     All podcasts (at least the ones on iTunes) use an xml file to store the podcast's metadata (show notes, title, episode number, recording/release date, etc). I would think most podcasters would like it if the program could find and update this file instead of editing the file manually after every episode.

iOS/Android/Windows Apps:
     I can dream, can't I?

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) 

Site Index

In The Beginning:

The Podside Project:

Lesson Learned:
About Me



The Podside Project: Introduction

Background:

     Most podcasters record their podcasts at home or in a studio and maybe use some VOIP (voice over IP) like Skype, Mumble, or TeamSpeak to have multiple people join in from different parts of the country/world and then upload their episode to their website and link it to iTunes. 
     Podside is a podcast (Podside.net) about a game (EVE Online) but what makes them special is how they deliver their content to their listeners. What makes Podside different is the fact they broadcast their episodes live. This of course is unusual and therefore the way they push out their live stream is convoluted involving a desktop with two sound cards (one with the audio output routed to the other card's audio input) to record not only the hosts microphone audio but the PC audio output containing the audio of the other hosts and guests. This recorded audio is then taken and pushed out to a dedicated broadcast server where the listeners can go to (Podside.net) and use the built in player to listen to the live broadcast.

The Basic Idea

Goals:

Generalized - To design and code a program with the purpose of recording 2 inputs, combining these audio inputs, convert them to mp3 format, and save the result while also sending it to a broadcast server for a live audience. Therefore, simplifying the process in general while also reducing the number of sound cards from 2 to 1, thus allowing laptops to be used to broadcast the live stream as well.

Technical - To design and code (in Java) a program with the purpose of recording 2 streaming inputs (microphone and PC audio output), combining these audio stream, convert (compress) the combined stream to mp3 format, and save the result to the hard drive (continuous writing to a file, possibly implemented as a separate thread) while also sending it (as an audio stream with no finite audio length, implemented as a separate thread) to a broadcast server for a live audience. Therefore, simplifying the process in general while also reducing the number of sound cards from 2 to 1, thus allowing laptops to be used to broadcast the live stream as well.

     I fully intend for this to be a open source project at this time, however, I see potential for this to one day become a 'full blown product' and thus I will say when I release the code (when there is something functional and worthy of being released) it will be 'open source' as in free to use by anyone for non-profit and/or educational purposes. 

Lessons Learned: Modular coding is great coding.

     Even though I was writing (what I thought to be) modular code I was shown a drastically better way of writing modular code, BUT EVEN MORE IMPORTANTLY this new method allows for coding in such a way that the code can be read as if it were almost 'complete' English sentences. This not only makes the code extremely readable but also makes updating code (more specifically updating someone else's code) much easier because if one thing breaks it is much more obvious where the logic error/error is coming from in the code. (More on this later, The Podside Project: The Design)

August 15, 2014

Layers of Complexity On Top of Exponentially Increasing Complexity:

Everything sounds or at least seems simple in the planning stages and then you break it down...and down...and down, at which point the design looks good and easy to implement. But then you realize it. It can be broken down even further, again and again.

Be ready to throw out your code if you start coding too soon, I have... several times.

Iteration, Iteration, Iteration:

Iteration is everything. 

Writing the same code over and over through iteration encourages learning through what you have done and/or done wrong. It always seems (at the time) that I am doing everything in a great or at least reasonable way, however, once I come back to it later I often end up asking, “Why did I do that?” or “What was I thinking?” even though I know what is going on in the code, it's just I know now there is a better/easier way of going about it.



Throw Away Your Code:

I have always found I tend to start writing code way too soon and so I continually find myself with lots of pieces of code in a file (code which might be functional but it is not connected to each other yet and therefore not compatible and thus useless). 
This always leads me to taking only a portion of this code, moving it to a new file/project and abandoning the old code to focus on a specific thing and build upon it as I am able to complete goals/design aspects. 

To some extent this is caused by poor planning and/or over enthusiasm and trying to write multiple parts of the code at once.

August 5, 2014

What's Your Motivation?

What's your motivation?

     My intentions for this blog is for me learn from and share my programming experiences, but mostly for myself to reflect on what I did, why I did it, and how I did it so that I can overcome obstacles, bad habits, and think of alternate ways of implementing a design.

Ben: You know, Thomas Edison tried and failed nearly 2,000 times to develop the carbonized
         cotton-thread filament for the incandescent light bulb.
Riley: Edison?
Ben: And when asked about it, he said "I didn't fail; I found out 2,000 ways how not to make a 
         light bulb." 
                                                                                                     - National Treasure, 00:29:58

     The following entries will be mostly brief (I hope) and mostly focusing on general programming concepts, object oriented programming, multi-threading, real-time applications, and breaking done a project in order to come up with a simple and straight forward design.

Disclaimer:
     I will do my best to check my spelling and grammar but remember I am doing this mostly for my benefit, but if you can also benefit...I'll gladly take credit for it. :)