Главная » Программирование звука » Музыкальные инструменты MIDI

0

Все  каналы  совместно  используют  объект  «карта  инструментов»,  отвечающий за   управление   набором   инструментов,   исполняющих   конкретное   музыкальное произведение.

Перед  проигрыванием  каждой  ноты  канал,  применяя  метод  Instrument,  делает  запрос  к  соответствующему  инструменту  из  карты  инструментов.  Данный метод предполагает три параметра.

Банк.  Стандарт  General  MIDI  определяет  всего  два  банка  инструментов:  один для  мелодических  инструментов  и  один  для  ритмических  (ударных).  Расширения стандарта (такие как Yamaha XG) устанавливают дополнительные банки. Банк выбирается  контроллерами  0x00  (старшие  7  бит)  и  0x20 (младшие  7  бит).  Следуя стандарту  Yamaha  XG,  я  определяю  мелодический  банк  General  MIDI  как  нулевой. а ритмический банк General MIDI как банк с кодом 0x3F80 (старшие 7 бит равны 0x7F, младшие 7 бит равны 0). (Стандарт Roland GS также использует нулевой  элемент  управления  для  задания  дополнительных  инструментов,  но  делает это несколько другим способом.)

Заметим, что в соответствии со стандартом General MIDI синтезатор в режиме последнего должен игнорировать команды выбора банка.

Программа. Это необязательно то же самое, что и инструмент. Например, ритмический банк General MIDI определяет всего одну программу, однако она содержит 47 инструментов. B мелодическом банке General MIDI 128 программ, каждая из них соответствует своему инструменту.

Нота. B некоторых программах для каждой клавиши используется свой инструмент. Это особенно характерно для программ, работающих с ударными инструментами (таких как ритмическая программа General MIDI) или со спецэффектами.

Полная реализация стандарта General MIDI потребовала бы 175 различных описаний инструментов. Для простоты класс MidiInstrumentMap в настоящем примере  управляет  всего  одним  инструментом   SineWaveInstrument (см.  раздел

«Генератор синусоиды» в главе 21).

B  более  полной  реализации  пришлось  бы  хранить  список  текущих  объектов инструментов, создавая новые только по необходимости.

Листинг 22.26. Карта инструментов MIDI

class MidiInstrumentMap {

private:

AbstractInstrument *_instr;

public:

enum {gmMelodyBank = 0, gmRhythmBank = (0x7f<<7)}; MidiInstrumentMap() {

//  _instr = new PluckedStringInstrument;

_instr = new SineWaveInstrument;

};

~MidiInstrumentMap() { delete _instr; }; AbstractInstrument *Instrument(int bank, int program, int

note);

void SamplingRate(long s) {

_instr->SamplingRate(s);

}

};

Метод Instrument весьма сложен в полной реализации. Вам придется выбирать  соответствующий  инструмент  в  зависимости  от  банка,  программы  и  ноты. Это   предполагает   достаточно   нетривиальное   управление   памятью.   Высококачественные  семплы  требуют  большого  объема  памяти,  поэтому  есть  смысл  сэкономить,  сохранив  в  памяти  только  те  инструменты,  которые  действительно  необходимы.  Если  вы  хотите  работать  непосредственно  со  звуковой  картой,  управление памятью  становится  еще  более  сложным,  так  как  большинство  звуковых  карт  обладают  ею  в  объеме,  достаточном  для  одновременного  хранения  лишь  небольшого количества семплов.

Листинг 22.27. Методы работы с картой инструментов MIDI

AbstractInstrument *MidiInstrumentMap::Instrument(

int bank, int program, int note) {

return _instr;

};

Желательно   иметь   возможность   просматривать,   какие   инструменты   используются   конкретным   музыкальным   произведением.   Представленный   ниже   фрагмент программы  просто  выводит  имя  инструмента  при  первом  его  выборе.  Заметим,  что здесь  присутствуют  две  разные  таблицы  инструментов:  одна  для  ритмических, другая для мелодических инструментов General MIDI.

Листинг 22.28. Просмотр имени инструмента

{

if((bank == gmRhythmBank)&&(program==0)) { static bool instrumentPrinted[128]; const struct {

int note;

const char *name;

} instruments[] = {

// Названия  инструментов  см. по   кодам в  табл. 22.6.

{35,"Acoustic Bass Drum"}, {36,"Bass Drum 1"},

{37,"Side Stick"}, {38,"Acoustic Snare"}, {39,"Hand

Clap"},

{40,"Electric Snare"}, {41,"Low Floor Tom"},

{42,"Closed Hi-Hat"}, {43,"High Floor Tom"},

{44,"Pedal Hi-Hat"}, {45,"Low Tom"}, {46,"Open Hi-Hat"},

{47,"Low-MidTom"}, {48,"Hi-MidTom"}, {49,"CrashCymbal

1"},

{50,"High Tom"}, {51,"Ride Cymbal 1"}, {52,"Chinese

Cymbal"},

{53,"Ride Bell"}, {54,"Tambourine"}, {55,"Splash Cymbal"},

{56,"Cowbell"}, {5 7,"CrashCymbal 2"}, {58,"Vibraslap"},

{59,"Ride Cymbal 2"}, {60,"Hi Bongo"}, {61,"Low Bongo"},

{62,"Mute Hi Conga"}, {63,"Open Hi Conga"}, {64,"Low

Conga"},

{65,"HighTimbale"}, {66,"LowTimbale"}, {67,"High

Agogo"},

{68,"Low Agogo"}, {69,"Cabasa"}, {70,"Maracas"},

{71,"Short Whistle"}, {72,"LongWhistle"}, {73,"Short

Guiro"},

{74,"Long Guiro"}, {75,"Claves"}, {76,"Hi Wood Block"},

{77,"Low Wood Block"}, {78,"Mute Cuica"}, {79,"Open

Cuica"},

{80,"Mute Triangle"}, {81,"Open Triangle"}, {0,0}

};

if (!instrumentPrinted[note]) {

// Инструмент:

cerr << "Instrument: "; int i=0; while((instruments[i].note != 0)

&& (instruments[i].note != note+1)) {

i++;

")\n";

}

}

}

if ((instruments[i].note == 0))

// Неизвестная нота … ударного  инструмента …

cerr << "Unknown Percussion.\n";

else

cerr << instruments[i].name << " (Note " << note <<

instrumentPrinted[note] = true;

if (bank == gmMelodyBank) {

static bool instrumentPrinted[128];

const char *instruments[] = {

// Названия  инструментов  по   порядку  номеров

// в  табл. 22.5.

"Acoustic Grand Piano", "Bright Acoustic Piano", "Electric Grand Piano", "Honky-tonk Piano", "Electric

Piano 1" ,

"Electric Piano 2", "Harpsichord", "Clavinet", "Celesta",

"Glockenspiel", "Music Box", "Vibraphone", "Marimba", "Xylophone", "Tubular Bells", "Dulcimer", "Drawbar

Organ" ,

"Percussive Organ", "Rock Organ", "Church Organ", "Reed Organ", "Accordion", "Harmonica", "Tango

Accordion",

"Acoustic Guitar (nylon)", "Acoustic Guitar (steel)",

Bass" , Bass 1" ,

"Electric Guitar (jazz)", "Electric Guitar (clean)", "Electric Guitar (mute)", "Overdriven Guitar", "Distortion Guitar", "Guitar Harmonics", "Acoustic

"Electric Bass (finger)", "Electric Bass (pick)", "Fretless Bass", "Slap Bass 1", "Slap Bass 2", "Synth

"Synth Bass 2", "Violin", "Viola", "Cello",

"Contrabass",

"Tremolo Strings", "Pizzicato Strings", "Orchestral

Harp",

Oohs", "Tuba",

"Timpani", "String Ensemble 1", "String Ensemble 2", "SynthStrings 1", "SynthStrings 2", "Choir Aahs", "Voice

"Synth Voice", "Orchestra Hit", "Trumpet", "Trombone", "Muted Trumpet", "French Horn", "Brass Section",

"SynthBrass 1",

"SynthBrass 2", "Soprano Sax", "Alto Sax", "Tenor Sax", "Baritone Sax", "Oboe", "English Horn", "Bassoon", "Clarinet", "Piccolo", "Flute", "Recorder", "Pan Flute", "Blown Bottle", "Shakuhachi", "Whistle", "Ocarina", "Lead 1 (square)", "Lead 2 (sawtooth)", "Lead 3

(calliope)",

"Lead 4 (chiff)", "Lead 5 (charang)", "Lead 6 (voice)", "Lead 7 (fifths)", "Lead 8 (bass+lead)", "Pad 1 (new

age)",

"Pad 2 (warm)", "Pad 3 (polysynth)", "Pad 4 (choir)", "Pad 5 (bowed)", "Pad 6 (metallic)", "Pad 7 (halo)", "Pad 8 (sweep)", "FX 1 (rain)", "FX 2 (soundtrack)", "FX 3 (crystal)", "FX 4 (atmosphere)", "FX 5

(brightness)",

"FX 6 (goblins)", "FX 7 (echoes)", "FX 8 (sci-fi)",

"Sitar", "Fiddle",

"Banjo", "Shamisen", "Koto", "Kalimba", "Bag pipe", "Shanai", "Tinkle Bell", "Agogo", "Steel Drums",

"Woodblock",

"Taiko Drum", "Melodic Tom", "Synth Drum", "Reverse

Cymba1",

"Guitar Fret Noise", "Breath Noise", "Seashore", "Bird Tweet", "Telephone Ring", "Helicopter",

"Applause", "Gunshot"

};

if(!instrumentPrinted[program]) {

// Инструмент:

cerr << "Instrument: " << instruments[program]; cerr << " (Program " << program << ")\n"; instrumentPrinted[program] = true;

}

}

}

Предостережения

Программа  воспроизведения,  разработанная  в  этой  главе,  будет  читать  любые стандартные файлы MIDI и воспроизводить записанную в них музыку. Моей целью, однако, являлось не создание синтезатора MIDI, а подробное исследование указанного стандарта. Еще многое требуется сделать, прежде чем можно будет сказать, что программа представляет из себя полезный инструмент воспроизведения MIDI. Много меньше предстоит сделать для реализации совместимости с General MIDI.

Наиболее  очевидный  недостаток  заключается  в  том,  что  не  осуществляется поддержка  всего  диапазона  инструментов  General  MIDI.  Добавление  новых  инструментов требует расширения объекта MidiInstrumentMap. Один из подходов разработка  набора  семплов  с  сохранением  их  в  файлах  и  загрузка  этих  инструментов объектом «карта инструментов» по мере необходимости. Более творческое решение  заключается  в  изучении  дополнительной  литературы  по  синтезу  звучания  инструментов  и  разработке  индивидуального  программного  кода  для  каждого инструмента.

Кроме   того,   есть   множество   неучтенных   деталей:   программа,   представленная  в  этой  главе,  не  поддерживает  монофонический/полифонический  режим,  управление  высотой  звука,  точную  настройку  и  многие  контроллеры,  регулярно  используемые композиторами, работающими с MIDI.

Источник: Кинтцель Т.  Руководство программиста по работе со звуком = A Programmer’s Guide to Sound: Пер. с англ. М.: ДМК Пресс, 2000. 432 с, ил. (Серия «Для программистов»).

По теме:

  • Комментарии