

Playing The Super Mario Bros. Theme With C#
source link: https://khalidabuhakmeh.com/playing-the-super-mario-bros-theme-with-csharp
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Playing The Super Mario Bros. Theme With C#
C# programming isn’t all about enterprise development, databases, and web APIs. Most folks likely got into software development because of video games. We wanted to create our heroes, worlds, and adventures. Being a millennial myself, Super Mario holds a place near and dear in my heart. So I thought I would take some inspiration and create a console application that plays the Super Mario Bros. theme, focusing on being cross-platform friendly and capable.
In this post, we’ll see how to use a cross-platform command-line utility, SoX, to play synthesized sounds from a console application.
Sound eXchange (SoX)
SoX is a cross-platform command-line utility that we can use to interact with various formats and audio files. Users can use the utility to apply effects and synthesize audio.
For the sake of this post, SoX is the best utility I could find that would work on all .NET platforms. For folks following along, they should be able to run this code sample regardless of their development environment. Before running the example, install the operating system-specific version of the utility on your development machine.
Since I run primarily on macOS, I used Homebrew to install SoX.
brew install sox
Windows users can download the latest SoX executable from the SourceForge release page. Windows users need to make sure they install SoX into a directory part of PATH
, as we’ll be invoking the utility via Process
calls.
Tones and Silence Records
We can break musical tones down into two parts: Frequency and Duration. There is also a particular instance of a musical tone, which we’ll define as silence or note with duration, but no frequency. We’ll use C# 9 records to define a structure for Tone
and Silence
, which will inherit from a Sound
base record.
public abstract record Sound(int Duration = 125)
{
public abstract void Play();
}
public record Silence(int Duration = 125) : Sound(Duration)
{
public override void Play()
{
// TODO: Implement Silence
}
}
public record Tone(int Frequency, int Duration = 125) : Sound(Duration)
{
public override void Play()
{
// TODO: Call SoX
}
}
Let’s start by defining the Play
method of Silence
. We have two options here; the first option is to call Thread.Sleep
for the duration of silence.
public record Silence(int Duration = 125) : Sound(Duration)
{
public override void Play()
{
Thread.Sleep(Duration);
}
}
The second option for silence is to use SoX to play a 0
frequency, which has no sound.
public record Silence(int Duration = 125) : Sound(Duration)
{
public override void Play()
{
var length = TimeSpan.FromMilliseconds(Duration).TotalSeconds;
var info = new ProcessStartInfo("play",
$"-n synth {length} sine 0") {RedirectStandardOutput = true};
var result = Process.Start(info);
result?.WaitForExit(Duration);
}
}
Let’s now implement the Play
method of our Tone
record.
public record Tone(int Frequency, int Duration = 125) : Sound(Duration)
{
public override void Play()
{
var length = TimeSpan.FromMilliseconds(Duration).TotalSeconds;
var info = new ProcessStartInfo("play",
$"-n -c1 synth {length} sine {Frequency}") {
RedirectStandardOutput = true
};
var result = Process.Start(info);
result?.WaitForExit(Duration);
}
}
We can pass the Frequency
in Hertz (Hz)
to our Tone
record’s positional parameter. It just a matter of waiting for the SoX process to complete, and then we can move on to the next tone.
It’s A Me, Mario! C# Code
Now that we have the building blocks of music let’s compose our Super Mario theme. Here is the entire example in a top-level statement file.
using System;
using System.Collections.Generic;
using System.Diagnostics;
// Super Mario Bros
// (Ported from http://www.portal42.net/mario.txt)
var music = new List<Sound> {
new Tone(659), new Tone(659), new Silence(), new Tone(659), new Silence(167), new Tone(523),
new Tone(659), new Silence(), new Tone(784), new Silence(375), new Tone(392), new Silence(375),
new Tone(523), new Silence(250), new Tone(392), new Silence(250), new Tone(330), new Silence(250),
new Tone(440), new Silence(), new Tone(494), new Silence(), new Tone(466), new Silence(42),
new Tone(440), new Silence(), new Tone(392), new Silence(), new Tone(659), new Silence(),
new Tone(784), new Silence(), new Tone(880), new Silence(), new Tone(698), new Tone(784),
new Silence(), new Tone(659), new Silence(), new Tone(523), new Silence(), new Tone(587),
new Tone(494), new Silence(), new Tone(523), new Silence(250), new Tone(392), new Silence(250),
new Tone(330), new Silence(250), new Tone(440), new Silence(), new Tone(494), new Silence(),
new Tone(466), new Silence(42), new Tone(440), new Silence(), new Tone(392), new Silence(),
new Tone(659), new Silence(), new Tone(784), new Silence(), new Tone(880), new Silence(),
new Tone(698), new Tone(784), new Silence(), new Tone(659), new Silence(), new Tone(523),
new Silence(), new Tone(587), new Tone(494), new Silence(375), new Tone(784), new Tone(740),
new Tone(698), new Silence(42), new Tone(622), new Silence(), new Tone(659), new Silence(167),
new Tone(415), new Tone(440), new Tone(523), new Silence(), new Tone(440),
new Tone(523), new Tone(587), new Silence(250), new Tone(784), new Tone(740), new Tone(698), new Silence(42),
new Tone(622), new Silence(), new Tone(659), new Silence(167), new Tone(698), new Silence(),
new Tone(698), new Tone(698), new Silence(625), new Tone(784), new Tone(740),
new Tone(698), new Silence(42), new Tone(622), new Silence(), new Tone(659), new Silence(167), new Tone(415),
new Tone(440), new Tone(523), new Silence(), new Tone(440), new Tone(523),
new Tone(587), new Silence(250), new Tone(622), new Silence(250), new Tone(587), new Silence(250), new Tone(523),
new Silence(1125), new Tone(784), new Tone(740), new Tone(698), new Silence(42), new Tone(622),
new Silence(), new Tone(659), new Silence(167), new Tone(415), new Tone(440), new Tone(523),
new Silence(), new Tone(440), new Tone(523), new Tone(587), new Silence(250), new Tone(784),
new Tone(740), new Tone(698), new Silence(42), new Tone(622), new Silence(), new Tone(659),
new Silence(167), new Tone(698), new Silence(), new Tone(698), new Tone(698), new Silence(625),
new Tone(784), new Tone(740), new Tone(698), new Silence(42), new Tone(622), new Silence(),
new Tone(659), new Silence(167), new Tone(415), new Tone(440), new Tone(523),
new Silence(), new Tone(440), new Tone(523), new Tone(587), new Silence(250),
new Tone(622), new Silence(250), new Tone(587), new Silence(250), new Tone(523),
new Silence(625),
};
music.ForEach(s => s.Play());
Console.Write(
@"
____▒▒▒▒▒
—-▒▒▒▒▒▒▒▒▒
—–▓▓▓░░▓░
—▓░▓░░░▓░░░
—▓░▓▓░░░▓░░░
—▓▓░░░░▓▓▓▓
——░░░░░░░░
—-▓▓▒▓▓▓▒▓▓
–▓▓▓▒▓▓▓▒▓▓▓
▓▓▓▓▒▒▒▒▒▓▓▓▓
░░▓▒░▒▒▒░▒▓░░
░░░▒▒▒▒▒▒▒░░░
░░▒▒▒▒▒▒▒▒▒░░
—-▒▒▒ ——▒▒▒
–▓▓▓———-▓▓▓
▓▓▓▓———-▓▓▓▓
");
// data structures for sounds
public abstract record Sound(int Duration = 125)
{
public abstract void Play();
}
public record Silence(int Duration = 125) : Sound(Duration)
{
public override void Play()
{
var length = TimeSpan.FromMilliseconds(Duration).TotalSeconds;
var info = new ProcessStartInfo("play",
$"-n synth {length} sine 0") {RedirectStandardOutput = true};
var result = Process.Start(info);
result?.WaitForExit(Duration);
}
}
public record Tone(int Frequency, int Duration = 125) : Sound(Duration)
{
public override void Play()
{
var length = TimeSpan.FromMilliseconds(Duration).TotalSeconds;
var info = new ProcessStartInfo("play",
$"-n synth {length} sine {Frequency}") {
RedirectStandardOutput = true
};
var result = Process.Start(info);
result?.WaitForExit(Duration);
}
}
Running the console application, we hear the Super Mario Bros. theme song.
Because @maartenballiauw nerd sniped me into it.
Here is @JetBrainsRider and @dotnet playing the Super Mario theme using SoX. https://t.co/1Oqpn6lMh3 pic.twitter.com/oXVIevRp68— Khalid ?? (@buhakmeh) December 15, 2020
To run this code on your development environment, you can clone this project from my GitHub repository.
I hope you enjoyed this blog post, and please share any compositions with me on Twitter by tagging me at @buhakmeh.
Recommend
-
11
A sealed copy of 'Super Mario Bros.' just sold for $660,000The sale shatters the previous $140,000 record for the game.Heritage AuctionsA nearly perfect copy of Super Mario Bros. for the NES has sold fo...
-
7
April 3, 2021 ...
-
9
Files Permalink Latest commit message Commit time
-
8
Here's The First Trailer For The Super Mario Bros Movie
-
6
TLDR; By pressing buttons really fast, we can write and execute our own code and win the game. The code we can write is very limited, but we have more than enough tools at our disposal to make some magic happen. You can use the comma...
-
11
In the new Super Mario Bros. Movie clip Toad is a fun guy / No (mushroom) cap.By Ash Parrish Dec...
-
12
Super Mario Bros. Movie Super Bowl ad revives live-action rap The Super Show lives on! By
-
14
The Super Mario Bros. Movie is coming a little early / The film’s release date has moved up by two days in the US and 60 other markets and is now set for April 5th. Its Japan premiere is still scheduled for April 28th...
-
9
The Super Mario Bros. Movie Just Had Its Release Date Bumped Up
-
10
Here’s the final trailer for The Super Mario Bros. Movie / One last look before Mario and friends head to theaters in April.By
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK