Introduction to the FMOD API

These are some notes and pointers about using the FMOD API, particularly if you (like me) don’t have a lot of previous programming experence. I won’t tell you anything that is not already in the official documentation but take this a condensed reference to use when coding or just to get familiar with the API.

Getting started

You can find the official documentation on the FMOD website. In case you don’t know, API stands for Application Programming Interface and is pretty much a bridge between two different computer environments like two different pieces of software. In this case, the FMOD API serves as the bridge between a game engine like Unity which scripts are written in C# and the FMOD engine itself.

The FMOD API can speak C, C#, C++ & JavaScript although not all functions are available in all languages. I will give C# and Unity examples here but these can be easily translated into other languages and engines.

Do you even need to use the API?

It depends. Out of the box, FMOD can be used on Unity or Unreal without much code work. You will be able to load banks and play audio events with just the components that come with the plugin but as soon as you need to do more complex things, you will probably need to use the API, at least in a few areas.

emitter.png

Studio vs Core API

Before diving in, you will see that FMOD differentiates between Studio & Core API. Most likely, you will just use the Studio API since it talks to Fmod Studio making things much easier for us sound designers.

The Core API, on the other hand, is completely standalone, allowing to integrate the fmod engine in a game without even using Fmod Studio. This is aimed for more bespoke integrations and deeper functionality that in most cases is not really needed but it is good to know it is there as an option.

So for now on, I will focus on the Studio API since is the one I’ve used myself.

Studio API Structure

On a high level, the studio API uses a series of concepts and classes that we should famliarize ourselves with. The main “brain” is the class RuntimeManager which will create and initialize an Studio::System instance which, in turn, will be the class we will use to call engine wide functions like setting global parameters.

By default, you don’t need to do anything for this to work as the fmod implementation in Unity or Unreal will get his ready for you. Studio::Bank can be then used to operate on the different banks themselves while Studio::Bus and Studio::VCA will allow you to get and set data on the mixer elements.

The concept of events in FMOD Studio is mapped to an Studio::EventDescription so if you want to do anything related to individual events that is what you will use. But keep in mind that you can have many instances of an event, so the API allow us to affect each of these through Studio::EventInstance. To be able to do this, you will need to cache a reference to each instance you play if you want to have full control of them. Usually, we don’t need to cache one-shots instances since we don’t need to affect them once played.

Also, remember that snapshots, when played, are also considered event instances so you can have all the same functionality for them and I would personally recommend creating a dedicated snapshot manager to keep track of them.

With that basic structure out of the way, let’s see what the API offers.

Studio API: Types

FMOD defines a bunch of types which will be very useful to get information about the audio engine. This are just a few commonly used types but there are many more.

Function Example Description Parameter Description FMOD.Studio.PARAMETER_DESCRIPTION Contains all the information in a parameter, including name min and max values, etc.. Loading State FMOD.Studio.LOADING_STATE Useful to know the loading state of different things, like banks and make sure we only use them when thay are loaded. Playback State FMOD.Studio.PLAYBACK_STATE; This one is SUPER useful so you can check if an event is playing, stopped, sustaining, etc... 3D Atrributes FMOD.ATTRIBUTES_3D The 3D position of an event or listener. This is a struct of simple vectors so you may need to convert it to something more usable like a Vector3.


Studio API: System

These calls allow you to talk to fmod in a general way, that would affect the whole fmod audio engine. Here are some of the most useful functions with some examples:

Function Example Description
Load Bank FMODUnity.RuntimeManager.LoadBank(bank, bool); Where "bank" is simply a string with the bank name. Make the bool true if you want to pre-load the sample data. I'm not sure why this can be done with just the RuntimeManager without using StudioSystem.
Unload Bank FMODUnity.RuntimeManager.UnloadBank(bank);
Get Bank FMODUnity.RuntimeManager.StudioSystem.getBank(path, out bank); Use this to grab a reference to a specific bank. "path" is the bank name (a string) and you will get a "Bank" struct type.
Get Bank Count FMODUnity.RuntimeManager.StudioSystem.getBankCount(out int count); Get the number of banks already loaded.
Get Bank List FMODUnity.RuntimeManager.StudioSystem.getBankList(out Bank[] array); Get an array of the type "Bank". Use with the one above if you need to get a reference to all loaded banks.
Get Listener Attributes FMODUnity.RuntimeManager.StudioSystem.getListenerAttributes(int listener, out FMOD.ATTRIBUTES_3D attributes, out FMOD.VECTOR attenuationposition); Use this to get a reference to the listener position which can be useful to calculate distances to emitters. The default listener is in index 0. There is also a set version of this function..
Get a Bus Reference FMODUnity.RuntimeManager.StudioSystem.getBus(path, out Bus bus); Get a bus reference so you can then use it. "path" is the bus string name. "bus:/" will always be the name of the master bus. You can also find a similar function for VCAs.
Get an event description FMODUnity.RuntimeManager.StudioSystem.getEvent(path, out EventDescription _event); This is very handy if you want to do something with an specific event. As usual, "path" is the string name.
Set a global parameter FMODUnity.RuntimeManager.StudioSystem.setParameterByName(name, value, ignoreseekspeed); Sets a value to a global parameter where "name" is a tring with the name of the parameter, "value" is a float and "ignoreseekspeed" is a bool.

Studio API: Bank

We won’t be able to do much until we have our banks loaded. Keep in mind that the master bank always needs to be loaded as this contains mixer information like buses, vcas or snapshots. Other than that, all other banks can be loaded one by one as needed. I talked about how to get a reference to a particular bank above, let’s now see what you can do with that reference:

Function Example Description
Get loading state Studio.Bank.getLoadingState(out LOADING_STATE state); We can check if a bank has finished loading before doing anything with it.
Load Sample data Studio.Bank.loadSampleData(); This will load all the audio files themselves into memory before any audio is played. Use this if the events are very time sensitive or you want to trade CPU for memory. There is also an unload method.
Unload bank Studio.Bank.unload(); Use this if you are sure you don't need the events contained on this bank anymore so we can save some memory.
Get the event count Studio.Bank.getEventCount(out int count); Check how many events the bank has.
Get event list Studio.Bank.getEventList(out EventDescription[] array); Use with the above method to get an arrray of event descriptions in case you then want to do something with them.

Studio API: EventDescription

You can find here all functions related to each specific event set in FMOD Studio. Before you use this, remember that you need to grab a reference to the event description using the method described in the section above so you can only do this once the bank containing the event is fully loaded. Once you have it, you can get some very usefu information from it. Here are some examples:

Function Example Description
Create Instance FMOD.Studio.EventDescription.createInstance(out EventInstance instance); Use this to create an instance which you must do before you play the event. It can be a good idea to cache the instance for use later.
Load Sample Data FMOD.Studio.EventDescription.loadSampleData(); This is very handy if you want to load the sample data for an event before you play it. Particularly useful for time sensitive events.
Is 3D FMOD.Studio.EventDescription.is3D(out bool is3D); Check if the event is 3D whcih would be determined by the event having an spatializer. Nice one if you create your own emitter or player.
Is Valid FMOD.Studio.EventDescription.isValid(); Use this one to make sure the event is not null and can be used.
Is Snapshot FMOD.Studio.EventDescription.isSnapshot(out bool snaphot); Check if a particular description is a snaphot.

Studio API: EventInstance

As mentioned before, we need to create an event instance in order to be able to play it or just do anything with them. Once this is done, we can have full control of the instance. Here are some useful methods:

Function Example Description
Play Instance FMOD.Studio.EventInstance.start(); Just play the instance. Basically, this will start the timeline, as set in fmod studio.
Stop Instance FMOD.Studio.EventInstance.stop(FMOD.Studio.STOP_MODE); Stops an instance. As you can see, we need to pass a stop mode which will determine if we respect any fades set in studio.
Release Instance FMOD.Studio.EventInstance.release(); This will tell the fmod engine that this instance can be deleted from memory. Use this after stopping an instance if you don't need it anymore. Important to prevent memory leaks.
Get playback state FMOD.Studio.EventInstance.getPlaybackState(out FMOD.Studio.PLAYBACK_STATE state) Use this to know the current state of the instance. Very useful if we want to check if the instance is playing before trying to stop it.
Set 3D Attributes FMOD.Studio.EventInstance.set3DAttributes(RuntimeUtils.To3DAttributes(position)); Sets the instance to a particular 3D position. Used to play audio in some specific place.
Attach to game object RuntimeManager.AttachInstanceToGameObject(instance, gameObject.transform, rigidBody); Use this for 3D events if, instead of playing in an specific place, you want to attach the sound to a game object.

Studio API: Bus & VCA

We can interact with the game’s mix by getting and setting values on buses and vcas. Check the system section to see how we can get a reference of a particular bus or vca but basically, we would need to know its name (as it was names in FMOD studio) as a string value so it could be a good idea to keep a reference of these somewhere in your code.

Let’s see a few examples of things we can do with buses and vcas:

Function Example Description
Set Bus volume Studio.Bus.setVolume(float volume); Sets a particular volume for this bus. There is also a get method.
Stop all events Studio.Bus.stopAllEvents(STOP_MODE mode); Stops all the events within a bus. Useful if you want to make sure all audio within a particular bus stops when unloading a level, for example. Notice that we need to pass the stop mode we wish to use.
Pause all events Studio.Bus.setPaused(bool pause); This will pause or unpause all the events contained in a bus. Use this for pause menus, for example.
Set VCA volume Studio.VCA.setVolume(float volume); Set volume on a VCA. Nice for the audio level settings.

In conclusion

I think if you understand how all the above work, that would be a very good start. Check out the FMOD reference docs for many useful examples and dont’ hesitate to drop me a line if you have any questions, I know some of this can be obscure until you use it for a while.

Exploring Sound Design Tools: Wormhole

Today I’m having a look at Zynaptiq’s Wormhole, a quite versatile warping, pitch bending plugin to use on sound effects, voice over and even musical elements.

Interface & Features

Wormhole has a few sections that operate more or less independently. It features the usual BIG wheel/knob thingy that other Zynaptiq’s pugins usually use, which in this case shifts the main warping effect up or down.

So if we look at the plugin’s signal flow, we see that it mainly consists of a warping section and shifting section. Both the dry and wet signals can be then delayed and finally reverb can be added at the very end or just after the main sections.

If we have a nother look at the UI, we can see where each of these sections live:

Warping

So let’s have a look at the Warp section which is the main feature of this plugin. Zynaptiq describes it as “proprietary time-domain local spectrum inversion“. Somewhat similar to a ring modulator but capable of producing unique sounds. Let’s see its settings:

Warp Depth: This adjust the frequency spectrum affected, low values will only affect high frequencies, while higher values will affect the whole spectrum but would give a milder result. To me, changing this value kind of feels like pitch shifting in a way. You can hear some examples here:

Poles: Increasing this value tightens up the frequencies and harmonics generated around an specific pitch while lower values create a more smeared sound. So use higher values if you want a thinned out type of sound. All the examples below where recorded while depth was at 50%.

Tilt: This shifts the whole warped spectrum up or down. So it kind of works like frequency shifting but with formant distorting qualities. This is what we control with the big circular knob.

Filter: This is just a simple low-pass filter than can be used after the warp and poles parameters (Pre) or afterthe tilt process (Post). The pre setting is generally better to create broken sounds, while post will result in cleaner results. Personally, I generally don’t notice much of a difference between pre and post.

Shifting

The shifting section is the other main feature Wormhole offers We find both frequency and pitch shifting. The difference between these two is that with frequency shifting, we are just moving all frequencies the same amount up or down which will results in more dramatic changes for low frequencies, musically speaking but far smaller changes for higher ones. In this sense, we could perfectly shift the fundamental note but the harmonics won’t be in the correct place since they are higher frequency. Pitch shifting, on the other hand, takes this into consideration and moves higher frequencies exponentially further away so the result sounds musical.

Let’s have a look at the settings that it offers so we can understand how it works:

Frequency Shift: It goes from -4000 Hz to +4000 Hz. Yeah, Hz, not semitones since this is frequency shift, not pitch shift. There are two modes here, linear and map. I see that map is the default option as it offers more granular change around 0 while the extremes change pitch in a more dramatic way.

Decay Time: Frequencies that play for longer than the desired time, will be discarded. So at the maximum value, nothing will change but as the value is lower the sound tends to dry out, reverb and noise can be reduced.

Pitch Shift: This is the proper pitch shift section and it uses 4 different modes:

  • Smooth: +/- 48 Semitones, optmized for low transient sounds.

  • Thight: +/- 48 Semitones, optimized for transient heavy sounds

  • Detune A: +/- 48 cents where L and R channels are shifted to produce a widening effect. Tight algorithm.

  • Detune B: +/- 48 cents where L and R channels are shifted to produce a widening effect. Smooth algorithm.

Other Features

We can also find a simple reverb with size and damp controls plus wet/dry controls for each individual section (Warp, Shift and Reverb). These three sections can change in routing order too.

Additionally, there is a blend section that offers something a bit more powerful than a simple master wet/dry mix control. When processing audio, you usually can hear the dry and wet at the same time, instead of a new, unique sound. Wormhole offers you a different way of blending dry and wet as the sound is gradually processed so you can have much smoother transitions and interesting intermediate states. Let’s see the modes it offers:

  • X-Fade: Normal dy/wet mix.

  • Morph A: Uses the properties of the wet signal to create the intermediate states.

  • Morph B: Uses the dry signal as the base, resulting in more subtle blending.

Finally, Wormhole has a delay value so you can blend dry and wet with a timing difference.

Processing Examples

Brief Source Control guide for Audio Peeps

Here is a summary of ideas and concepts about Source Control or Version Control that I wished I knew when I starting out in game audio since they can get a bif confusing.

What is Source Control?

Basically, It is a system used within software development to share and keep track of code and other assets. Since many people will have access to the same files, you can see how this can create conflicts if two people try to change the same thing at the same time. Source Control has features and workflows to allow people to safely work without conflicting with each other.

It also allows you to work with different versions of the same application which share some parts of the code. At the same time, in functions as an advanced backup because all the work is both locally on every developer computer and on a server somewhere. Because of this, is easy to go back to a previous version if needed, like if something breaks, for example.

So imagine something like Google Drive or Dropbox but far more advanced so multiple users can seamlessly work at the same time and with different partial collections of files from a common pool in the cloud.

In summary, Source Control is a fancy way of sharing files between people in a way that allows for multiple versions and conflicts can be minimized and/or resolved when they arrive.

Git

This is one of the most popular pieces of software to do Source Control and you will probably see it all around. Since it was developed by Linus Torvalds (yeah the guy who is the reason Linux is called that way), it is a free and open source so anyone can use it.

As far as I can see, Git was 87.2% of Source Control software in 2018 so it is clearly the King.

What can be confusing at first, is that Git, more than an application itself, is a system or protocol. Git can be used on the terminal but more usually people use a Client, which is a dedicated App with a GUI (Graphical User Interface) so it is easier to use.

Fundamentally, you can use Git purely locally but usually it is hosted online so many people can access the same repository. So you need some server somewhere to do this.

In conclusion, Git seems to be the most used Source Control software and it is really a protocol that can be used by different clients and using different online services for hosting. Let’s see these:

Git Hosting & Clients

GitHub: This is a company owned by Microsoft which offers free online hosting for Git repositories. Many important open soruce projects are on Github, like Bitcoin. For commercial and more complex projects, Github also have paid options.

GitHub Desktop: This is a client, a software with a GUI that uses the Git protocol and can be used with Github hosting or really any other Git hosting (Even local).

GitLab: This is another popular online hosting service for Git projects.

Bitbucket: This is yet another online hosting service for Git owned by Atlassian, who also owns Jira (a task management) and Confluence (wikis) which are also popular in the game development industry.

Sourcetree: This is a popular client with a GUI to work with Git repositories and it is also owned by Atlassian.

Fork: Yet another client to use Git with.

TortoiseGit: One more Git client which integrates with the Windows File Explorer.

There are many, many more hosting services and clients but those above are some of the most popular.

Apache Subversion (SVN)

This is a completely different ecosystem and procol for source control. It uses similar concepts as Git but on other aspects is quite different. I’ve seen SVN used for larger files like art and audio within game development.

TortoiseSVN is a popular SVN client which integrates with the Windows File Explorer.

Perforce or P4

This another Source Control protocol software, quite popular in software and game development.

Terminology & Workflows

Now that we know a bit about the ecosystem, let’s see some of the concepts that Source Conctrol uses. This can be applied to any system but is mostly oriented towards Git.

repository is like a project that you create withing the Git system. So an app or a game will generally be one repository that is then shared by all the users.

When you want to get the repository in your local computer this is called Clonning. When doing this, you choose a folder in your drive and the Git client will download all the content. Once you do this, you have access to all the files, or to be precise to a version of all these files from the moment you did the clonning.

Although you are at first clonning the whole repository, while you work you are always dealing with branches. These are different versions of the software or game that are used by the team. Usually, there is a stable main branch called master or develop which functions as the principal branch where all other branches usually eventually point to.

After you clone the repo, if someone else updated it later, you will get “behind”. Source Control doesn’t usually work like Drive or Dropbox, where things are automatically updated. In contrast, you have update it manually. This may seem like a weakness but it is actually a strength. You need to have full control of when you are behind, ahead or just in sync with the server’s repository, depending on the situation.

Generally, if you are not working on anything at the moment, you want to be up to date with the master branch. For this, you switch to that branch (you check out the branch) and use the Pull action, which just pretty much checks if there is new stuff on the server and downloads it. In the case of SVN, this is action is called Update, which makes sense.

Keep in mind that when getting the latest version, you don’t get the whole thing again, just whatever is new or was changed, which makes things much faster. But what happens of you are the one who makes the changes? In this case, the simplest thing to do is to just send your changes to the server. In order to do this, git has two different steps which can be confusing. Before we go into those, we need to find whatever files we have changed and select them to make sure those are the changes that we want to upload. This part is important because usually there will be other local changes that we don’t really want to get into the server.

So after making sure that we have chosen the correct changes, we need to do these two step which are usually done at once but is important that you know the difference between them. The first is a Commit. This is just saying to the repo, hey I want to change these files and here is a brief description of what this change does. Once you do a commit, you have updated your local version of the branch where you are working on, but the server (or your co-workers) still have no idea that this change has occurred. The next step is a Push and that’s just the action of uploading your changes to the server for everyone to see.

As you can see, in the heart of this Commit and Push workflow is the isea of a Change, that is, the files that you have modified in respect to the server version that sits in the repo. Sometimes, you will make unintended changes which will break things. Since you are working with Source Control, you can always revert these changes, which will change the file back to its original state, which should be the same that exists in the server so no harm done.

Something else that it is important to know: You don’t usually work directly on the master or develop branch. This branch is usually reserved for an estable version of the game or software so people shouldn’t directly push things to it. That’s why we use branches. You would usually do your work in a branch you create, check that all works as intended and then push your changes to a server version of your own branch. Once that is done, you will create a Pull Request, from your branch to the estable one and usually someone with more seniority will check that all looks good and then accept the pull request. Once done, the result is sometimes called a Merge, since your branch is merging into the master branch.

And that’s all I have, it was quite a lot at once if you are new to this but I hope this works as an introduction from which you can expand as you get more and more into game development.

Learning C# Notes - Part IV: Methods

Here are my notes on eveyrthing related to methods.

Methods Basics

  • We can think of methods as the different actions that our classes can perform so they are the basic building blocks that determine how a class behaves.

  • Sometimes they are called ‘Functions’.

  • We first define a method using paretheses () after the name. Method names usually start with a capital letter.

  • After defining the method, we can call it from somewhere else.

  • See an example below. We first define a method and then it is called from some other method definition.

class Program { void FirstMethod() { // code to be executed } void OtherMethod() { //Some More code FirstMethod(); } }

Return Types & Passing Parameters

  • Methods can return a variable after they run, which needs to be specified when we define the method.

  • If a method returns no value, it will be of type void.

  • While return types are like outputs, we can also input information into a method. These inputs are called parameters.

  • For a method to take parameters, we must define them when we define the method.

  • A method can take multiple parameters.

  • We can give parameters a default value by using the equals sign when defining the method.

  • The ‘params’ keyword can also be used to make a parameter optional.

    • To be precise, it allows you to pass any amount of elements in an argument's array and if you pass 0 elements this is in practice like making the argument optional.

    • The params keyword can only be used once per method and must be the last argument.

int SumNumbers(int num1, int num2) { return num1 + num2; } void MyMethod(string country = "Norway") { Console.WriteLine(country); }

Method Overloading

  • Multiple methods can have the same name and vary in how many parameters they take and even their return types.

  • This is useful when you need a method that can perform generally the same function but using different types of information.

  • We just define and call them as normal using the same method name.

  • See the example below. Both methods will just sum numbers but they can take different type of variables as values.

int SumNumbers(int num1, int num2) { return num1 + num2; } float SumNumbers(float num1, float num2) { return num1 + num2; }

Calling Method from other classes & Static Methods

  • When working in Unity with C#, most of the time, each class lives in its own script file.

  • Is very common for a class to call another class’ method.

  • This is usually done by typing the name of the class followed by a full stop and then the name of the method, ending in paretheses.

  • If we want to call a method within a class without instatiating that said class, a possible solution could be to make the method static when defining it.

Unity Methods

  • Unity includes some important methods that we can use on Monobehaviour type scripts.

  • Awake() is the first method called and it should usually be used for initializing things. Is only called once.

  • Start() is also called once after Awake() but inly if the script component is enabled.

  • Update() is called on every frame that the script component is active.

  • LateUpdate() is called every frame but only after everything on Update() has finished executing.

  • FixedUpdate() is the same as above but it has the frequency of the physics system.

  • OnEnable() is called when the gameobject containing the script is enabled and becomes active.

  • OnDisable() is called when the gameobject containing the script is disabled or destroyed.

Learning C# Notes - Part III: Selection & Operation Statements

So up until now I’ve left my notes on classes, which work as functional units in c# and on variables which store all sorts of data.

Next thing would be to use that data residing within classes and do something with it. Selection statements allow us to so different thing depending on the data itself while operation statements gives you the ability of parsing through collections of data to read or modify them.

Conditional Statements (If-else)

  • This is the most basic selection statement.

  • We analyze a condition and determine what to do if it is true.

  • Since a condition can only be either true or false, we must always analyze a boolean variable or any method that returns a bool.

  • We can use any logic expression that would result in a boolean like 3 > number.

  • We can also determine what we want to happen if the condition is not true with the else keyword.

  • Additionally, we can check further conditions with the else if keyword.

  • See examples:

int health;

if (health < 10) 
{
    //Player is hurt.  
}
else if (health < 50) 
{
    //Player is low health.  
}
else 
{
    //Player is healthy. 
}

Switch Statement

  • The conditional structure explained above is good when you just have a few possible options but sometimes you have a bunch of cases and you want to do something different for each one.

  • We can also include a default case which will be used if the expression passed is not found.

  • The syntaxis is a bit different that conditional statements, see below:

enum playerState; //This struct contains a list of states the player can be in.

switch (playerState) 
{
  case playerState.poisoned
    //We play a poisend snapshot.
    break;
  case playerState.burning
    //We play a burning snapshot.
    break;
  case playerState.confused
    //We play a confused snapshot.
    break;
  case playerState.dead
    //We play a death snapshot.
    break;
  case default
    //We play the normal snapshot.
    break;
}

Logical Operators

  • If we want to do more complex statements we can use logical operators to add certain conditions and logic.

  • We use “&&” as an AND statement when we want to check that two or more conditions are true.

  • We use “||” as an OR statement if we want to do something when either condition is true. Only one needs to be true.

  • We use “!” as a NOT statement to signify that we want to check the opposite of a condition. In other words, the “!” operator inverts a bool, turning a true into false.

  • When checking that something is bigger or smaller that our condition, we use “<“ and “>”.

  • We can also use “<=” to check is something is smaller or equal and “>=” to check if it is bigger or equal.

  • We use “==” to check if a variable equals another.

  • See these in action below:

// NOT
bool result = true;
if (!result)
{
    Console.WriteLine("The condition is true (result is false).");
}
else
{
    Console.WriteLine("The condition is false (result is true).");
}

// Short-circuit AND
int m = 9;
int n = 7;
int p = 5;
if (m >= n && m >= p)
{
    Console.WriteLine("Nothing is larger than m.");
}

// AND and NOT
if (m >= n && !(p > m))
{
    Console.WriteLine("Nothing is larger than m.");
}

// Short-circuit OR
if (m > n || m > p)
{
    Console.WriteLine("m isn't the smallest.");
}

// NOT and OR
m = 4;
if (!(m >= n || m >= p))
{
    Console.WriteLine("Now m is the smallest.");
}

Iteration Statements: foreach

  • We use this iterator to go through all the values on a list, dictionary or other collection.

  • We use the “in” keyword to specify the type of element to be examined and where it comes from.

  • Is important to note that “foreach” creates a copy of the collection when iterating through it so we can’t alter it directly.

  • If we want to alter a collection as we loop through it we need to use a “for” loop (see below).

  • "foreach” is more readable and clean but performs worst than a for loop.

var fibNumbers = new List<int> { 0, 1, 1, 2, 3, 5, 8, 13 };
int count = 0;
foreach (int element in fibNumbers)
{
    Console.WriteLine($"Element #: ");
    count++;
}
Console.WriteLine($"Number of elements: ");

Iteration Statements: for

  • This will execute the code inside as long as the condition evaluated is true.

  • We initialize an iterator value and alter it on each cycle.

  • It is very useful for checking all the elements in a collection or do something a certain number of times.

  • It allows you to directly alter the values of the collection that you are examining.

  • Is important to note that we first check the condition and then execute the code between { }.

int[] Numbers = {1,2,3,4,5,6}
contant someConstantValue;

for (int i = 0; Numbers.Length; i++) 
{
    Numbers[i] = Numbers[i]*someConstantValue;    
}

Iteration Statements: do while

  • This basically works like a for loop but the main difference is that the code is executed first and then the condition is checked.

  • So in other words a “do while” statement will always execute the code between { } at least once.

  • You can use the keyword “break” to exit the loop at anytime.

int n = 0;
do
{
    Console.WriteLine(n);
    n++;
} while (n < 5);

Iteration Statements: while

  • “while” can also be used by itself to to something while a certain condition is true.

int n = 0;
while (n < 5)
{
    Console.WriteLine(n);
    n++;
}