OSC - Tutorial

This tutorial uses Microsoft VisualC++ v6.0. The complete source code for the finished project can be found in the 'OSC\samples\OSCTutorial\' directory.

Step 1 - Creating the project

Start VisualC++

Create a new project by selecting 'File | New | Projects | Win32 Console Application'. Name the new application 'OSCTutorial'. Press [OK]. Select (*) An empty project and press [Finish].

Add the path of the OSC include files to the projects by selecting 'Project | Settings | C++ | Preprocessor' and typing the path in the field named 'Additional include directories', for instance './../../include'.

Add the OSC library (.lib) to the project by selecting 'Project | Settings | Link | General' and adding the full path to the osc_ds.lib file to the end of the field named 'Object/library modules', for instance './../../lib/osc_ds.lib'. (The _ds part in the filename stands for Debug SingleThreaded and is the run-time library used by this project (as shown in 'Project | Settings | C++ | Code Generation | Use run-time library'). Read the file OSC/lib/readme.txt for details. ).

In FileView, right click on the project and select 'Add Files to Project...'. Type in the filename 'OSCTutorial.cpp', press [OK], then [Yes].

Open the new file from the FileView in the 'Source Files' section. Answer [Yes] when VisualC++ asks if you want to create a new file.

Type in the following text:

#include <stdio.h>
#include <conio.h>

#include <OSC_MIDIOutput.h>

void main()
{
    printf("--- The OSC Tutorial ---\n\n");

    OSC_MIDIOutput midiout;
    OSC_MIDIMessage msg;

    midiout.Open(0);
    msg.SetMessageType(OSC_MIDI_MESSAGE_NOTE_ON);
    msg.SetChannel(0);
    msg.SetNoteNumber(60);
    msg.SetNoteVelocity(127);
    midiout.SendMIDIMessage(msg);
    Sleep(1000);
    msg.SetMessageType(OSC_MIDI_MESSAGE_NOTE_OFF);
    midiout.SendMIDIMessage(msg);
    printf("Hit a key to exit\n");
    getch();
    midiout.Close();
};

Compile the program and run it.

The program will play a MIDI piano note for 1 second on the MIDI device 0 (provided MIDI device 0 is a GM device and it is available).

 

Step 2 - Selecting MIDI Output Device

We want to let the user select which MIDI output device to use. Replace midiout.Open(0) with the following:

    printf("Select MIDI Output Device:\n");

    OSC_StringArray devicelist;
    midiout.GetListOfDevices(devicelist, true);

    for (int i=0; i<devicelist.size(); i++)
        printf(" %s\n", devicelist[i].c_str());

    int midioutdevice;
    scanf("%d", &midioutdevice);

    midiout.Open(midioutdevice);

 

Step 3 - MIDI Input

We'd like the user to be able to play the MIDI notes himself using his MIDI keyboard.

We create our own MIDIInput class, inheriting from OSC_MIDIInput, and overriding the MIDIInput(...) function. The source now looks like this:

#include <stdio.h>
#include <conio.h>

#include <OSC_MIDIOutput.h>
#include <OSC_MIDIInput.h>

class TutorialMIDIInput : public OSC_MIDIInput
{
private:
    OSC_MIDIOutput *m_midiout;
public:
    void SetMIDIOutput(OSC_MIDIOutput *out)
    {
        m_midiout = out;
    };
    virtual void MidiInput(OSC_MIDIMessage message)
    {
        m_midiout->SendMIDIMessage(message);
    };
};

void main()
{
    printf("--- The OSC Tutorial ---\n\n");

    OSC_MIDIOutput midiout;
    OSC_MIDIMessage msg;

    printf("Select MIDI Output Device:\n");

    OSC_StringArray devicelist;
    midiout.GetListOfDevices(devicelist, true);

    for (int i=0; i<devicelist.size(); i++)
        printf("   %s\n", devicelist[i].c_str());

    int midioutdevice;
    scanf("%d", &midioutdevice);

    midiout.Open(midioutdevice);

    TutorialMIDIInput midiin;

    printf("Select MIDI Input Device:\n");

    midiin.GetListOfDevices(devicelist, true);

    for (i=0; i<devicelist.size(); i++)
        printf("   %s\n", devicelist[i].c_str());

    int midiindevice;
    scanf("%d", &midiindevice);

    midiin.SetMIDIOutput(&midiout);
    midiin.Open(midiindevice);
    midiin.Start();

    printf("Listening to MIDI Device %d, playing on MIDI Device %d\n", 
        midiindevice, midioutdevice);

    printf("Hit a key to exit\n");
    getch();

    midiin.Stop();
    midiin.Close();
    midiout.Close();

};


Step 4 - Selecting bank and preset for a SoundFont device

We now add the ability to select which bank and which preset to use. The following code will only work on systems with SoundFont compatible devices installed. You will also have to download and install Creative Labs' SoundFont Management System. Visit the download page for a link.

Add the path to the sfman.h file (included in the SoundFont Management System) to the projects include files ('Project | Settings | C++ | Preprocessor'  - 'Additional include directories'), or just copy it (sfman.h) to the OSC\include folder.

Include the OSCSFManager class: #include <OSC_SFManager.h>

List the available SoundFont devices, similar to what we've done for midi in and out:

    // SoundFonts
    
    OSC_SFManager sfman;
    sfman.Init();
    
    printf("Select SoundFont device (should match the MIDI Output Device):\n");
    
    sfman.GetListOfDevices(devicelist, true);

    for (i=0; i<devicelist.size(); i++)
        printf(" %s\n", devicelist[i].c_str());

    int soundfontdevice;
    scanf("%d", &soundfontdevice);

    sfman.Open(soundfontdevice);

List all the banks loaded by that device:

    // Banks

    printf("Select Bank:\n");

    for (i=0; i<128; i++)
        if (sfman.BoolIsMIDIBankUsed(i))
        {
            std::string name;
            if ( (sfman.GetLoadedBankDescriptor(i, name)) != OSC_ERR_OK)
                break;
            else
                printf("[%d] %s\n", i, name.c_str());
        }

    int bank;
    scanf("%d", &bank);

List all the presets in that bank:

    // Presets

    printf("Select Preset:\n");

    for (i=0; i<128; i++)
    {
        std::string presetname;
        sfman.GetLoadedPresetDescriptor(bank, i, presetname);
        if (!presetname.empty())
        {
            printf("[%d] %s\n", i, presetname.c_str());
        };
    }

    int preset;
    scanf("%d", &preset);

Send bank change and program change to the MIDI output device:

    // Set MIDI bank & preset

    // CC0 bank
    msg.Clear();
    msg.SetMessageType(OSC_MIDI_MESSAGE_CONTROL_CHANGE);
    msg.SetChannel(0);
    msg.SetControllerNumber(OSC_MIDI_MESSAGE_CONTROL_BANK_SELECT);
    msg.SetControllerValue(bank);
    midiout.SendMIDIMessage(msg);
    // PgChg program
    msg.Clear();
    msg.SetMessageType(OSC_MIDI_MESSAGE_PROGRAM_CHANGE);
    msg.SetChannel(0);
    msg.SetProgram(preset);
    midiout.SendMIDIMessage(msg);

Well, that's pretty much it. We now have a program that lets the user select a MIDI input and output device, select a soundfont (bank) and select a preset. The program receives MIDI input and echoes the input to the output, using the selected bank and preset.

The complete source code looks like this:

#include <stdio.h>
#include <conio.h>

#include <string>

#include <OSC_MIDIOutput.h>
#include <OSC_MIDIInput.h>
#include <OSC_SFManager.h>

class TutorialMIDIInput : public OSC_MIDIInput
{
private:
    OSC_MIDIOutput *m_midiout;
public:
    void SetMIDIOutput(OSC_MIDIOutput *out)
    {
        m_midiout = out;
    };
    virtual void MidiInput(OSC_MIDIMessage message)
    {
        m_midiout->SendMIDIMessage(message);
    };
};

void main()
{
    printf("--- The OSC Tutorial ---\n\n");

    OSC_MIDIOutput midiout;
    OSC_MIDIMessage msg;

    // MIDI Output

    printf("Select MIDI Output Device:\n");

    OSC_StringArray devicelist;
    midiout.GetListOfDevices(devicelist, true);

    for (int i=0; i<devicelist.size(); i++)
        printf(" %s\n", devicelist[i].c_str());

    int midioutdevice;
    scanf("%d", &midioutdevice);

    midiout.Open(midioutdevice);

    TutorialMIDIInput midiin;

    // MIDI Input
    
    printf("Select MIDI Input Device:\n");

    midiin.GetListOfDevices(devicelist, true);

    for (i=0; i<devicelist.size(); i++)
        printf(" %s\n", devicelist[i].c_str());

    int midiindevice;
    scanf("%d", &midiindevice);

    midiin.SetMIDIOutput(&midiout);
    midiin.Open(midiindevice);

    // SoundFonts
    
    OSC_SFManager sfman;
    sfman.Init();
    
    printf("Select SoundFont device (should match the MIDI Output Device):\n");
    
    sfman.GetListOfDevices(devicelist, true);

    for (i=0; i<devicelist.size(); i++)
        printf(" %s\n", devicelist[i].c_str());

    int soundfontdevice;
    scanf("%d", &soundfontdevice);

    sfman.Open(soundfontdevice);

    // Banks

    printf("Select Bank:\n");

    for (i=0; i<128; i++)
        if (sfman.BoolIsMIDIBankUsed(i))
        {
            std::string name;
            if ( (sfman.GetLoadedBankDescriptor(i, name)) != OSC_ERR_OK)
                break;
            else
                printf("[%d] %s\n", i, name.c_str());
        }

    int bank;
    scanf("%d", &bank);

    // Presets

    printf("Select Preset:\n");

    for (i=0; i<128; i++)
    {
        std::string presetname;
        sfman.GetLoadedPresetDescriptor(bank, i, presetname);
        if (!presetname.empty())
        {
            printf("[%d] %s\n", i, presetname.c_str());
        };
    }

    int preset;
    scanf("%d", &preset);

    // Set MIDI bank & preset

    // CC0 bank
    msg.Clear();
    msg.SetMessageType(OSC_MIDI_MESSAGE_CONTROL_CHANGE);
    msg.SetChannel(0);
    msg.SetControllerNumber(OSC_MIDI_MESSAGE_CONTROL_BANK_SELECT);
    msg.SetControllerValue(bank);
    midiout.SendMIDIMessage(msg);
    // PgChg program
    msg.Clear();
    msg.SetMessageType(OSC_MIDI_MESSAGE_PROGRAM_CHANGE);
    msg.SetChannel(0);
    msg.SetProgram(preset);
    midiout.SendMIDIMessage(msg);

    midiin.Start();

    printf("Listening to MIDI Device %d, playing on MIDI Device %d\n", 
        midiindevice, midioutdevice);

    printf("Hit a key to exit\n");
    getch();

    midiin.Stop();
    sfman.Close();
    midiin.Close();
    midiout.Close();

};

And that concludes this tutorial.

 


The complete HammerSound website, including all text, images and databases,  is copyright (c) 1997-2000 Thomas Hammer
[HammerSound Home]