Click here to Skip to main content
Click here to Skip to main content

MP3 Sound Recording Tool

By , 18 Sep 2011
 
mp3recording_src

Introduction

Here is a single dialog utility for recording from the sound card in MP3 format. This is simply a repackaging of a console application described by rtybase in an article which appeared in here on CodeProject a while ago.

Background

I have put this utility together fairly quickly as a replacement for some DOS batch files which I used to drive the mp3_stream.exe with. I then soon realised that it would be useful to add a duration timer so that a recording can be ended whilst the computer is left unattended. I found this to be particularly useful when recording longer sessions, some of which can be over six hours long.

Using the Utility

The dialog shows the settings which represent the command line arguments for mp3_stream.exe, such as the volume (value 15 is recommended), bit rate (in kilo bits per second) e.g. 128. The Device and line names are shown in dropdown list boxes. The total duration of the recording can be optionally specified, and a file name which the recording is to be saved as can be browsed for using the standard Windows Save File As dialog. All configuration settings are saved on closing down the utility, and are automatically reloaded the next time it is launched.

Windows 7 Usability Notes

Since I first published this article, more and more people started using it with post-Windows XP operating systems, naturally. The issue encountered when using Windows 7 (and Windows Vista too) is that the operating system both disables and hides the Stereo Mix device by default, even if it is available through the soundcard's driver. Overcoming this issue is fairly straightforward, as follows:

  1. Right-click on the speaker icon in the system tray and select Recording devices (you can also bring up this dialog through Windows control panel)
  2. Right-click inside the dialog to bring up the context menu, and select Show Disabled Devices
  3. Again, right-click inside the dialog to bring up the context menu, and this time select Show Disconnected Devices
  4. The above two steps will make Stereo Mix visible, right-click on it and select Enable
  5. Close the dialog by pressing the OK button

Now the next time you launch the utility, you will be able to select the Stereo Mix device and Master Volume line.

How the Code Works

mp3_stream.exe itself is a C++ application, which uses the LAME open source library to carry out the MP3 encoding. To communicate to LAME using a .NET application, one could go about this in several ways. For example, one could add a thin interface layer of managed C++ to the mp3_stream.exe source code and recompile it so that it can be accessed via .NET. Or, one could add a thin interface layer on the C# project side (using [DllImport]) to access the LAME DLL functionality directly.

However, mp3_stream.exe does in fact already provide an API which is perfectly accessible from .NET. This is perhaps not what one would normally think of as an API in a conventional sense, because it is simply the command line arguments supported by mp3_stream.exe. Nevertheless, it is a programmable interface which provides access to the desired functionality perfectly well. For example, to enumerate the sound cards supported by the system, mp3_stream.exe is invoked with a -device argument. To do this programmatically, System.Diagnostics.Process is used to spawn a mp3_stream.exe process providing it with the appropriate arguments. This is done by the Execute method, which in turn calls the InitiateMP3StreamProcess method:

private void InitiateMP3StreamProcess(Process proc, string arguments)
{
    proc.StartInfo.CreateNoWindow = true;
    proc.StartInfo.WorkingDirectory = Application.StartupPath;
    proc.StartInfo.FileName = "mp3_stream.exe";
    proc.StartInfo.Arguments = arguments;
    proc.StartInfo.UseShellExecute = false;
    proc.StartInfo.RedirectStandardOutput = true;
    proc.StartInfo.RedirectStandardError = true;
    proc.StartInfo.RedirectStandardInput = true;
    proc.Start();
}

private List<string> Execute(string command)
{
    Process devicesProc = new Process();
    InitiateMP3StreamProcess(devicesProc, command);
    devicesProc.WaitForExit();

    List<string> response = new List<string>();
    string line;
    while ((line = devicesProc.StandardOutput.ReadLine()) != null)
    {
        response.Add(line);
    }

    return response;
}

The method Execute is called with a string which specified the command line argument which needs to be passed to the mp3_stream.exe process:

Execute("-devices");

This is used, in conjunction with using the -device argument, to iteratively populate the DeviceLines dictionary with all the available devices and lines:

private void PopulateDevices()
{
    List<string> devices = Execute("-devices");
    foreach (string device in devices)
    {
        Devices.Items.Add(device);

        DeviceLines.Add(device, new List<string>());
        List<string> lines = Execute(string.Format("-device=\"{0}\"", device));
        foreach (string line in lines)
        {
            DeviceLines[device].Add(line);
        }
    }
}    

Saving and Retrieving the Configuration

For added convenience, the tool automatically saves its current configuration on exit. This configuration is then reloaded the next time the tool is launched. This is achieved by handling the form's FormClosing and Load events:

private void Record_FormClosing(object sender, FormClosingEventArgs e)
{
    SaveCurrentConfiguration();
}

private void Record_Load(object sender, EventArgs e)
{
    RestorePreviousConfiguration();
}

The SaveCurrentConfiguration and RestorePreviousConfiguration methods in turn use the Settings class to access the application configuration parameters:

private void RestorePreviousConfiguration()
{
    Settings config = Settings.Default;
    Volume.Text = config.Volume;
    BitRate.Text = config.BitRate;
    if (Devices.Items.Contains(config.Device))
    {
        Devices.SelectedItem = config.Device;
    }
    if (Lines.Items.Contains(config.Line))
    {
        Lines.SelectedItem = config.Line;
    }
}

private void SaveCurrentConfiguration()
{
    Settings config = Settings.Default;
    config.Volume = Volume.Text;
    config.BitRate = BitRate.Text;
    if (Devices.SelectedItem != null)
    {
        config.Device = Devices.SelectedItem.ToString();
    }
    if (Lines.SelectedItem != null)
    {
        config.Line = Lines.SelectedItem.ToString();
    }

    config.Save();
}

Recording

Once configured and the Record button is pressed, the utility displays the time left for the recording to complete. This is done using a timer, which updates a progress bar and a textual display of time remaining:

private void UpdateTimeRemaining(TimeSpan timeSpan)
{
    TimeRemaining.Text = string.Format("Time remaining: {0}:{1}:{2}",
	timeSpan.Hours, timeSpan.Minutes, timeSpan.Seconds);
}

private void Timer_Tick(object sender, EventArgs e)
{
    DateTime timeNow = DateTime.Now;
    if (timeNow >= EndTime)
    {
        OnStopRecording();
    }
    else
    {
        TimeSpan timeRemaining = EndTime - timeNow;
        UpdateTimeRemaining(timeRemaining);
        TimeSpan timeElapsed = timeNow - StartTime;
        TimeSpan totalDuration = EndTime - StartTime;
        double percentageElapsed =
         (timeElapsed.TotalMilliseconds / totalDuration.TotalMilliseconds) * 100;
        if (percentageElapsed > 0)
        {
            Progress.Value = (int)percentageElapsed;
        }
        else
        {
            Progress.Value = 0;
        }
    }
}

The recording operation itself is invoked by the Click event handler of the Record button:

private void StartRecording_Click(object sender, EventArgs e)
{
    string args = 	string.Format
	("-device=\"{0}\" -line=\"{1}\" -v={2} -br={3} -sr=32000",
            Devices.SelectedItem.ToString(),
            Lines.SelectedItem.ToString(),
            Volume.Text,
            BitRate.Text);

    RecordingProc = new Process();
    InitiateMP3StreamProcess(RecordingProc, args);
    StartRecording.Enabled = false;
    StopRecording.Enabled = true;

    // Use timed recording if user has specified a duration,
    // otherwise do not initiate the timer and simply return.
    TimeSpan recordingDuration = new TimeSpan(Duration.Value.Hour,
                                              Duration.Value.Minute,
                                              Duration.Value.Second);
    if(recordingDuration.TotalSeconds == 0)
        return;

    StartTime = DateTime.Now;
    EndTime = StartTime.Add(recordingDuration).AddSeconds(TimerFudgeFactor);
    Timer.Start();
}

You may have noticed TimerFudgeFactor and wondered why it is needed. I found that the total time of recordings made using mp3_stream.exe is always shorter than expected by around 3 seconds. This could be an artefact of the encoding process throwing away a small chunk of data at the end of its buffer for some reason. TimerFudgeFactor has a value of 3 (seconds) and seems to work reasonably well for short and long recording alike.

And Finally...

I hope that you find this utility useful. I have certainly had made a lot of use out of the original mp3_stream.exe application, and thought it would be good to contribute back to CodeProject by posting these usability improvements.

History

  • 6th February, 2010: Initial post
  • 18th September, 2011: Added "Windows 7 Usability Notes" section

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

firas sawaf
Software Developer
United Kingdom United Kingdom
Member
I work in financial software. When programming for fun, I like solving problems involving some maths or a puzzle of some kind.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionUpdated utility and append MP3 filememberMember 794828611 Jan '13 - 12:07 
Any idea when your next update will be released?
 
Is it possible to open an existing MP3 file and add (append) to the end of it?
 
Thank you
AnswerRe: Updated utility and append MP3 filememberfiras sawaf11 Jan '13 - 21:21 
Next update? Good point, I have a few ideas in mind, so may well do soon. Please let me know of any features which you'd like to see, and I'll do my best.
 
I like your idea about appending files, though I can foresee an issue with that. Windows seems to cache somewhere the length of any given MP3 file. So if the file length changes from 2 minutes to 5 minutes, next time you open it in media player it will still show as 2 minute long.
 
By the way, if you are into editing audio, I would recommend audacity[^] it's completely free and you can do some amazing stuff with it!
Questionvb.net codemembernewcoder19 Aug '12 - 11:43 
is there any way to do this code in vb.net
i tried to convert it but i got some issue like imports Record.Properties
and i can't add lame_enc.dll as reference..and i dont see it as reference in the c# project i wonder how you did it
Generalnot workingmemberlouis sawaf26 Sep '11 - 9:55 
mr firas sawaf my driver is unsporting to your download! Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( Frown | :( :(
GeneralRe: not workingmemberfiras sawaf26 Sep '11 - 9:57 
It looks like you need to update your soundcard drivers with the latest ones from the manufacturer.
GeneralRe: not workingmemberlouis sawaf26 Sep '11 - 9:58 
will that cost anything?
GeneralRe: not workingmemberfiras sawaf26 Sep '11 - 9:59 
No, not really. Driver updates are normally completely free.
GeneralRe: not workingmemberlouis sawaf26 Sep '11 - 10:00 
ok thank you
Laugh | :laugh:
Questionsame but in vb.netmemberelpaez15 Sep '11 - 10:59 
I'm finding this project but in vb.net, all translation software i used finally take me to a debugger fail, can anyone help me with this?
GeneralReplace Savemembercrimsonfire0325 Apr '11 - 11:28 
When I am saving mp3 with the same name that already exist, It show the error with System.IO.File.Move()
"Cannot create a file when that file already exists"
I don't want to change name, solve that please. Thank you Big Grin | :-D

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 18 Sep 2011
Article Copyright 2010 by firas sawaf
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid