This tutorial uses Microsoft VisualC++ v6.0. The complete source code for the finished project can be found in the 'OSC\samples\OSCTutorial\' directory.
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).
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); |
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(); }; |
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]