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

0

B  некоторой  степени  все  представленные  мной  классы  чтения  аудиофайлов являются   интерпретаторами.   Класс   WaveRead,   например,   интерпретирует   заголовок   и   информацию   о   сжатии   для   формирования   потока   значений   AudioSample.

Инструкции,  которые  должен  интерпретировать  проигрыватель  MIDI,  гораз-

до  сложнее,  и  класс  MidiRead,  о  котором  идет  речь  в  этой  главе,  отражает  эту сложность.

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

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

При  ответе  на  эти  запросы  объект  MidiRead просматривает  список  событий

и  передает  запросы  к  объектам  каналов   настоящему  сердцу  процесса  воспроиз-

ведения.  Мой проигрыватель  MIDI  состоит из 16  синтезаторов, один для  каждого канала.  Объект  MidiRead сохраняет  партитуру  MIDI  и  использует  ее  для  управления  каналами,  отвечающими  за  создание  и  управление  нотными  объектами,  которые в действительности и формируют звук. Каждый канал объединяет свои выходные   ноты,   а   объект   MidiRead складывает   выходную   информацию   всех каналов для получения конечного звука.

Каналы  совместно  используют  ряд  ресурсов.  Объекты  каналов  должны  в  конечном счете получить объекты инструментов (смотри главу 21) и использовать их для создания нот. Я создал один объект MidiInstrumentMap, который следит за

множеством объектов инструментов, и объект MidiTuningMap, который знает,

как преобразовывать значения нот MIDI в абсолютные значения высоты.

Листинг 22.16. Программа midi.h

#ifndef MIDI_H_INCLUDED

#define MIDI_H_INCLUDED

#include "audio.h"

#include "instrumt.h"

#include "sampled.h"

#include "plucked.h"

#include <iostream>

#include <cmath>

bool IsMidiFile(istream &file);

class MidiRead;

class MidiRead: public AudioAbstract {

private:

// Информация  о  проигрываемой  песне.

MidiInstrumentMap *_instrumentMap; MidiTuningMap *_tuningMap; MidiChannelAbstract *_channel[16];

public:

MidiInstrumentMap *InstrumentMap() { return _instrumentMap; } MidiTuningMap *TuningMap() { return _tuningMap; }

private:

int _fileType;     // Тип  файла  Standard MIDI.

int _numberTracks; // Количество  дорожек.

int _timeFormat;   // Формат   кодировки  времени.

unsigned long _samplesRemaining;

// Количество отсчетов

// до   следующего  события.

private:

// Общая  информация.

void ReadTracks();  // Читаем  файл   в память. void ReadHeader();  // Читаем  файл   в память.

void PostProcess();   // Постобработка потока  событий.

istream &_stream;    // Читаемый  файл.

public:

MidiRead(istream &input = cin);

~MidiRead();

protected:

void MinMaxSamplingRate{long *min, long *max, long *preferred)

{

*min = *max = *preferred = 11025;

}

void MinMaxChannels(int *min, int *max, int *preferred) {

*min = *max = *preferred = 1;

}

size_t GetSamples(AudioSample *buffer, size_t numSamples);

};

#endif

Листинг 22.17. Программа midi.cpp

#include <cstring>

#include <istream>

#include <cstdio>

#include <cmath>

#include "audio.h"

#include "instrumt.h"

#include "sampled.h"

#include "plucked.h"

#include "midi.h"

// Чтение  файла.

MidiRead::MidiRead(istream &s):AudioAbstract(), _stream(s) {

// Формат   файла: MIDI.

cerr << "File Format: MIDI\n";

_currentEvent = _events = 0;

for(int i=0;i<16;i++) _channel[i] = 0;

_instrumentMap = new MidiInstrumentMap;

_tuningMap = new MidiTuningMap;

}

MidiRead::~MidiRead() {

MidiEvent *pEvent, *pNext = _events;

while (pNext) {                 // Стираем список  событий.

pEvent = pNext;

pNext = pEvent->next;

delete pEvent;

}

for(int i=0; i< 16; i++) {     // Удаляем объекты  каналов.

if (_channel[i])

delete _channel[i];

}

delete _instrumentMap;          // Удаляем карту  инструментов.

delete _tuningMap;              // Удаляем карту  настройки.

};

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

По теме:

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