Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (WinAPI, Konsole) » MIDI Dateien auslesen

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
17.11.2005, 22:37 Uhr
~ddih
Gast


Hallo zusammen,

nachdem ich beim googlen nicht wirklich fündig geworden bin stelle ich meine Frage mal hier ins Forum. Weiss jemand vielleicht wie ich eine MIDI Datei auslesen kann sprich die einzelnen Events bekomme. Kann ich da auch MCI verwenden oder gibt es vielleicht bereits gute Libs dafür ? habe von der midifile.dll gehört ist (soweit ich weiss) aber nur für win 98/NT.

Vielen dank im voraus
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
18.11.2005, 15:40 Uhr
BoBtheREapER
kein job für nen BoB


kann openal nicht auch midi dateien auslesen?
--
"Zwei Dinge sind unendlich: Das Universum und die menschliche Dummheit. Aber beim Universum bin ich mir nicht ganz sicher." - Albert Einstein
www.blue-xenon.de.vu
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
18.11.2005, 15:45 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


hatte da mal ne klasse geschrieben, weiß nicht ob die mit "normalen" midi files klarkommt, mit dem xmidi von glaub yamaha schon:

loadMID.cpp

C++:
#include "main.h"
#include "load/loadMID.h"

int loadMID(MID_Data *data, const char *file)
{
  // ist file ein gültiger Pointer?
  if(!file)
  {
    printf("loadMID: ERROR: file is null\n");
    return -1;
  }

  // ist data ein gültiger Pointer?
  if(!data)
  {
    printf("loadMID: ERROR: data is null\n");
    return -1;
  }

#ifndef USE_MIXER
  printf("loadMID: skipped\n");
  return 0;
#else

  // DAT zum Lesen öffnen
  FILE *mid_data = fopen(file,"rb");

  // Öffnen fehlgeschlagen
  if(!mid_data)
  {
    printf("loadMID: ERROR: %s\n", strerror(errno) );
    return -1;
  }

  unsigned long value, bobtype, type;

  // Group-Identifier einlesen
  bobtype = fget32(mid_data);

  // Überprüfen
  if(bobtype != 0x464F524D) // != "FORM"
  {
    printf("loadMID: ERROR: Group Identifier (FORM) not found: No valid XMIDI-File!!!\n" );
    return -1;
  }

  // Blocklänge lesen
  unsigned long form_length;
  form_length = fget32(mid_data);

  type = fget32(mid_data);

  if(type == 0x584D4944) // != "XMID"
  {
    printf("loadMID: WARNING: XMIDI does not have XDIR!!!\n" );
    data->track_count = 1;
  }
  else if(type != 0x58444952) // != "XDIR"
  {
    printf("loadMID: ERROR: Type Identifier (XDIR/XMID) not found: No valid XMIDI-File!!!\n" );
    return -1;
  }
  else
  {
    unsigned long x = 4;
    while(x < form_length)
    {
      value = fget32(mid_data);

      switch(value)
      {
      case 0x494E464F: // "INFO"
        {
          // Blocklänge einlesen
          unsigned long length;
          length = fget32(mid_data);

          // bei ungerader zahl "aufrunden"
          if (length%2)
            length++;
          x += length;

          if(length != 2)
          {
            printf("loadMID: ERROR: Invalid chunk length for INFO block: %ld < 2!!!\n", length );
            return -1;
          }

          fread(&data->track_count, 2, 1, mid_data);
          length -= 2;

          // Unvollständig gelesen?!?
          if (length != 0)
          {
            printf("loadMID: WARNING: INFO-Block abgeschnitten: %ld Bytes zu wenig/zuviel!\n", length );
          }
        } break;
      case 0x43415420: // "CAT "
        {
          // Blocklänge einlesen
          unsigned long length;
          length = fget32(mid_data);

          // bei ungerader zahl "aufrunden"
          if (length%2)
            length++;

          x += length;

          type = fget32(mid_data);
          if(type != 0x584D4944)
          {
            printf("loadMID: ERROR: Type Identifier (XMID) not found: No valid XMIDI-File!!!\n" );
            return -1;
          }
        } break;
      }
    }

    if(data->track_count == 0)
    {
      printf("loadMID: ERROR: XMIDI-File does not contain any tracks!!!\n" );
      return -1;
    }

    if(data->track_count > 256)
    {
      printf("loadMID: ERROR: XMIDI-File does contain too many tracks (%d > 256)!!!\n", data->track_count);
      return -1;
    }

    unsigned short track_nr = 0;
    while(track_nr < data->track_count)
    {
      // Block-Identifier einlesen
      value = fget32(mid_data);

      switch(value)
      {
      case 0x464F524D: // "FORM"
        {
          // Unbekannte Daten einlesen
          unsigned char unknown[4];
          fread(unknown, 1, 4, mid_data);
        } break;
      case 0x584D4944: // "XMID"
        {
        } break;
      case 0x54494D42: // "TIMB"
        {
          // Blocklänge einlesen
          unsigned long length;
          length = fget32(mid_data);

          // bei ungerader zahl "aufrunden"
          if (length%2)
            length++;

          // Rest des Blocks einlesen (unbekannte Daten)
          unsigned char *unknown2 = new unsigned char[length+1];
          size_t read = fread(unknown2, 1, length, mid_data);
          if(read <= length)
            length -= (unsigned long)read;

          // Unvollständig gelesen?!?
          if (length != 0)
          {
            printf("loadMID: WARNING: TIMB-Block abgeschnitten: %ld Bytes zu wenig/zuviel!\n", length );
          }

          delete[] unknown2;
        } break;
      case 0x45564E54: // "EVNT"
        {
          // Blocklänge einlesen
          unsigned long length;
          length = fget32(mid_data);

          // bei ungerader zahl "aufrunden"
          if (length%2)
            length++;

          // Rest des Blocks einlesen (Track Daten)
          data->tracks[track_nr].data = new unsigned char[length+1];
          size_t read = fread(data->tracks[track_nr].data, 1, length, mid_data);
          if(read <= length)
            length -= (unsigned long)read;

          data->tracks[track_nr].data_length = (unsigned int)read;

          // Unvollständig gelesen?!?
          if (length != 0)
          {
            printf("loadMID: WARNING: EVNT-Block abgeschnitten: %ld Bytes zu wenig/zuviel!\n", length );
          }

          track_nr++;
        } break;
      }
    }
  }

  data->file = new CXMIDIFile(data);
  data->file->Convert();

  fclose(mid_data);

#endif // !USE_MIXER

  return 0;
}

void freeMID(MID_Data *data)
{
#ifdef USE_MIXER
  for(unsigned int x = 0; x < 256; x++)
  {
    delete[] data->tracks[x].data;
    data->tracks[x].data = NULL;

    delete[] data->tracks[x].converted;
    data->tracks[x].converted = NULL;
  }

  delete data->file;
  data->file = NULL;
#endif // USE_MIXER

  data->track_count = 0;

  memset(data, 0, sizeof(MID_Data));
}



loadMID.h

C++:
class CXMIDIFile;

typedef struct MID_Data {
  unsigned short track_count;
  MID_Track tracks[256];

  CXMIDIFile *file;
} MID_Data;

typedef struct MID_Event {
   int            time;
   unsigned char  status;

   unsigned char  data[2];

   unsigned int    len;
   unsigned char  *buffer;
   int            duration;
   MID_Event     *next_note;
   unsigned int   note_time;
   MID_Event     *next;
} MID_Event;

typedef struct MID_Track {
  unsigned char *data;
  unsigned int data_length;

  unsigned char *converted;
  unsigned int converted_length;

  MID_Event *events;
  unsigned int event_count;
} MID_Track;



XMIDIFile.cpp

C++:
#include "main.h"
#include "midi/XMIDIFile.h"

CXMIDIFile::CXMIDIFile(MID_Data *data)
{
  MIDData = data;
  position = 0;
  current = NULL;

  memset(bank127, 0, sizeof(bank127));
}

CXMIDIFile::~CXMIDIFile()
{
  for(unsigned int track_nr = 0; track_nr < MIDData->track_count; track_nr++)
  {
    if(MIDData->tracks[track_nr].event_count > 0)
    {
      MID_Event *event, *next;
      event = MIDData->tracks[track_nr].events;
      next = MIDData->tracks[track_nr].events;
      while ((event = next))
      {
        next = event->next;
        if ((event->status>>4) == 0xF && event->buffer)
          delete[] (event->buffer);
        delete event;
      }
    }
  }
}

#define PATCH_VOL_PAN_BIAS 5

GammaTable<unsigned char> CXMIDIFile::VolumeCurve(128);

const char CXMIDIFile::mt32asgm[128] =
{
  0,   // 0    Piano 1
    1,   // 1    Piano 2
    2,   // 2    Piano 3 (synth)
    4,   // 3    EPiano 1
    4,   // 4    EPiano 2
    5,   // 5    EPiano 3
    5,   // 6    EPiano 4
    3,   // 7    Honkytonk
    16,  // 8    Organ 1
    17,  // 9    Organ 2
    18,  // 10   Organ 3
    16,  // 11   Organ 4
    19,  // 12   Pipe Organ 1
    19,  // 13   Pipe Organ 2
    19,  // 14   Pipe Organ 3
    21,  // 15   Accordion
    6,   // 16   Harpsichord 1
    6,   // 17   Harpsichord 2
    6,   // 18   Harpsichord 3
    7,   // 19   Clavinet 1
    7,   // 20   Clavinet 2
    7,   // 21   Clavinet 3
    8,   // 22   Celesta 1
    8,   // 23   Celesta 2
    62,  // 24   Synthbrass 1 (62)
    63,  // 25   Synthbrass 2 (63)
    62,  // 26   Synthbrass 3 Bank 8
    63,  // 27   Synthbrass 4 Bank 8
    38,  // 28   Synthbass 1
    39,  // 29   Synthbass 2
    38,  // 30   Synthbass 3 Bank 8
    39,  // 31   Synthbass 4 Bank 8
    88,  // 32   Fantasy
    90,  // 33   Harmonic Pan - No equiv closest is polysynth(90) :(
    52,  // 34   Choral ?? Currently set to SynthVox(54). Should it be ChoirAhhs(52)???
    92,  // 35   Glass
    97,  // 36   Soundtrack
    99,  // 37   Atmosphere
    14,  // 38   Warmbell, sounds kind of like crystal(98) perhaps Tubular Bells(14) would be better. It is!
    54,  // 39   FunnyVox, sounds alot like Bagpipe(109) and Shania(111)
    98,  // 40   EchoBell, no real equiv, sounds like Crystal(98)
    96,  // 41   IceRain
    68,  // 42   Oboe 2001, no equiv, just patching it to normal oboe(68)
    95,  // 43   EchoPans, no equiv, setting to SweepPad
    81,  // 44   DoctorSolo Bank 8
    87,  // 45   SchoolDaze, no real equiv
    112, // 46   Bell Singer
    80,  // 47   SquareWave
    48,  // 48   Strings 1
    48,  // 49   Strings 2 - should be 49
    44,  // 50   Strings 3 (Synth) - Experimental set to Tremollo Strings - should be 50
    45,  // 51   Pizzicato Strings
    40,  // 52   Violin 1
    40,  // 53   Violin 2 ? Viola
    42,  // 54   Cello 1
    42,  // 55   Cello 2
    43,  // 56   Contrabass
    46,  // 57   Harp 1
    46,  // 58   Harp 2
    24,  // 59   Guitar 1 (Nylon)
    25,  // 60   Guitar 2 (Steel)
    26,  // 61   Elec Guitar 1
    27,  // 62   Elec Guitar 2
    104, // 63   Sitar
    32,  // 64   Acou Bass 1
    32,  // 65   Acou Bass 2
    33,  // 66   Elec Bass 1
    34,  // 67   Elec Bass 2
    36,  // 68   Slap Bass 1
    37,  // 69   Slap Bass 2
    35,  // 70   Fretless Bass 1
    35,  // 71   Fretless Bass 2
    73,  // 72   Flute 1
    73,  // 73   Flute 2
    72,  // 74   Piccolo 1
    72,  // 75   Piccolo 2
    74,  // 76   Recorder
    75,  // 77   Pan Pipes
    64,  // 78   Sax 1
    65,  // 79   Sax 2
    66,  // 80   Sax 3
    67,  // 81   Sax 4
    71,  // 82   Clarinet 1
    71,  // 83   Clarinet 2
    68,  // 84   Oboe
    69,  // 85   English Horn (Cor Anglais)
    70,  // 86   Bassoon
    22,  // 87   Harmonica
    56,  // 88   Trumpet 1
    56,  // 89   Trumpet 2
    57,  // 90   Trombone 1
    57,  // 91   Trombone 2
    60,  // 92   French Horn 1
    60,  // 93   French Horn 2
    58,  // 94   Tuba  
    61,  // 95   Brass Section 1
    61,  // 96   Brass Section 2
    11,  // 97   Vibes 1
    11,  // 98   Vibes 2
    99,  // 99   Syn Mallet Bank 1
    112, // 100  WindBell no real equiv Set to TinkleBell(112)
    9,   // 101  Glockenspiel
    14,  // 102  Tubular Bells
    13,  // 103  Xylophone
    12,  // 104  Marimba
    107, // 105  Koto
    111, // 106  Sho?? set to Shanai(111)
    77,  // 107  Shakauhachi
    78,  // 108  Whistle 1
    78,  // 109  Whistle 2
    76,  // 110  Bottle Blow
    76,  // 111  Breathpipe no real equiv set to bottle blow(76)
    47,  // 112  Timpani
    117, // 113  Melodic Tom
    116, // 114  Deap Snare no equiv, set to Taiko(116)
    118, // 115  Electric Perc 1
    118, // 116  Electric Perc 2
    116, // 117  Taiko
    115, // 118  Taiko Rim, no real equiv, set to Woodblock(115)
    119, // 119  Cymbal, no real equiv, set to reverse cymbal(119)
    115, // 120  Castanets, no real equiv, in GM set to Woodblock(115)
    112, // 121  Triangle, no real equiv, set to TinkleBell(112)
    55,  // 122  Orchestral Hit
    124, // 123  Telephone
    123, // 124  BirdTweet
    94,  // 125  Big Notes Pad no equiv, set to halo pad (94)
    98,  // 126  Water Bell set to Crystal Pad(98)
    121  // 127  Jungle Tune set to Breath Noise
};

int CXMIDIFile::Convert(void)
{
  for(unsigned int track_nr = 0; track_nr < MIDData->track_count; track_nr++)
  {
    ConvertTrackToList(&MIDData->tracks[track_nr]);
    ConvertListToMTrk(&MIDData->tracks[track_nr]);
  }
  return 0;
}

int CXMIDIFile::ConvertTrackToList(MID_Track *track)
{
  int            time = 0; // 120th of a second
  unsigned int   data;
  int            end = 0;
  unsigned int   status = 0;
  int            play_size = 3;
  int            retval = 0;

  position = 0;

  first_state fs;
  memset(&fs, 0, sizeof(first_state));

  while (!end && position < track->data_length)
  {
    GetVLQ2(track, data);
    time += data;
    status = (unsigned int)track->data[position++];

    switch (status >> 4)
    {
    case MIDI_STATUS_NOTE_ON:
      retval |= 1 << (status & 0xF);
      ConvertNote(track, time, status, play_size);
      break;

    case MIDI_STATUS_NOTE_OFF:
      ConvertNote(track, time, status, 2);
      break;

      // 2 byte data
    case MIDI_STATUS_AFTERTOUCH:
    case MIDI_STATUS_CONTROLLER:
    case MIDI_STATUS_PITCH_WHEEL:
      ConvertEvent(track, time, status, 2, fs);
      break;

      // 1 byte data
    case MIDI_STATUS_PROG_CHANGE:
    case MIDI_STATUS_PRESSURE:
      ConvertEvent(track, time, status, 1, fs);
      break;

    case MIDI_STATUS_SYSEX:
      if (status == 0xFF)
      {
        unsigned int pos = position;
        unsigned int data = track->data[position++];

        if (data == 0x2F)
          end = 1;
        else if (data == 0x51)
        {
          GetVLQ(track, data);
          position += data;
          break;
        }

        position = pos;
      }
      ConvertSystemMessage(track, time, status);
      break;
    }

  }
  current = track->events;

  position = 0;
  MID_Track test;
  test.events = track->events;
  test.data_length = 5;
  test.data = new unsigned char[5];
  test.data[0] = 0x51;
  test.data[1] = 0x03;
  test.data[2] = 0x07;
  test.data[3] = 0xA1;
  test.data[4] = 0x20;
  ConvertSystemMessage(&test, 0, 0xFF);

  delete[] test.data;

  ApplyFirstState(track, fs, retval);

  return retval;
}

int CXMIDIFile::GetVLQ(MID_Track *track, unsigned int &quant)
{
  int i;
  quant = 0;
  unsigned char data = 0;

  for (i = 0; i < 4; i++)
  {
    data = track->data[position++];
    quant <<= 7;
    quant |= data & 0x7F;

    if (!(data & 0x80))
    {
      i++;
      break;
    }
  }
  return i;
}

int CXMIDIFile::GetVLQ2(MID_Track *track, unsigned int &quant)
{
  int i;
  quant = 0;
  unsigned char data = 0;

  for (i = 0; i < 4; i++)
  {
    data = track->data[position++];
    if (data & 0x80)
    {
      position--;
      break;
    }
    quant += data;
  }
  return i;
}

int CXMIDIFile::PutVLQ(MID_Track *track, unsigned int value, bool write, unsigned int pos /*= 0*/)
{
  int buffer;
  int i = 1;
  buffer = value & 0x7F;
  while (value >>= 7)
  {
    buffer <<= 8;
    buffer |= ((value & 0x7F) | 0x80);
    i++;
  }

  if (!write)
    return i;

  for (int j = 0; j < i; j++)
  {
    track->converted[pos++] = buffer & 0xFF;
    buffer >>= 8;
  }

  return i;
}

int CXMIDIFile::ConvertNote(MID_Track *track, const int time, const unsigned char status, const int size)
{
  unsigned int delta = 0;
  int data;

  data = track->data[position++];

  CreateNewEvent(track, time);
  current->status = status;

  current->data[0] = data;
  current->data[1] = track->data[position++];

  // Volume modify the note on's, only if converting
  if ((current->status >> 4) == MIDI_STATUS_NOTE_ON && current->data[1])
    current->data[1] = VolumeCurve[current->data[1]];

  if (size == 2)
    return 2;

  // XMI Note On handling

  int i = GetVLQ(track, delta);
  current->duration = delta;

  // This is an optimization
  MID_Event *prev = current;

  // Create a note off
  CreateNewEvent(track, time+delta);

  current->status = status;
  current->data[0] = data;
  current->data[1] = 0;

  // Optimization
  current = prev;

  return i + 2;
}

int CXMIDIFile::ConvertEvent(MID_Track *track, const int time, const unsigned char status, const int size, first_state &fs)
{
  //   Uint32 delta=0;
  int data;

  data = track->data[position++];

  // Bank changes are handled here
  if ((status >> 4) == 0xB && data == 0)
  {
    data = track->data[position++];

    bank127[status&0xF] = false;

    return 2;
  }

  // Handling for patch change mt32 conversion, probably should go elsewhere
  if ((status >> 4) == 0xC && (status&0xF) != 9)
  {
    data = mt32asgm[data];
  }

  // Disable patch changes on Track 10 is doing a conversion
  else if ((status >> 4) == 0xC && (status&0xF) == 9)
  {
    return size;
  }

  CreateNewEvent(track, time);
  current->status = status;

  current->data[0] = data;

  // Check for patch change, and update fs if req
  if ((status >> 4) == 0xC)
  {
    if (!fs.patch[status&0xF] || fs.patch[status&0xF]->time > time)
      fs.patch[status&0xF] = current;
  }

  // Controllers
  else if ((status >> 4) == 0xB)
  {
    // Volume
    if (current->data[0] == 7)
    {
      if (!fs.vol[status&0xF] || fs.vol[status&0xF]->time > time)
        fs.vol[status&0xF] = current;
    }
    // Pan
    else if (current->data[0] == 10)
    {
      if (!fs.pan[status&0xF] || fs.pan[status&0xF]->time > time)
        fs.pan[status&0xF] = current;
    }
  }

  if (size == 1)
    return 1;

  current->data[1] = track->data[position++];

  // Volume modify the volume controller, only if converting
  if ((current->status >> 4) == MIDI_STATUS_CONTROLLER && current->data[0] == 7)
    current->data[1] = VolumeCurve[current->data[1]];

  return 2;
}

int CXMIDIFile::ConvertSystemMessage(MID_Track *track, const int time, const unsigned char status)
{
  int i = 0;

  CreateNewEvent(track, time);
  current->status = status;

  // Handling of Meta events
  if (status == 0xFF)
  {
    current->data[0] = track->data[position++];
    i++;
  }

  i += GetVLQ(track, current->len);

  if (!current->len)
  {
    current->buffer = NULL;
    return i;
  }

  current->buffer = new unsigned char[current->len];
  memset(current->buffer, 0, current->len);

  memcpy(current->buffer, &track->data[position], current->len);
  position += current->len;

  return i + current->len;
}

void CXMIDIFile::CreateNewEvent(MID_Track *track, int time)
{
  if (!track->events)
  {
    track->events = current = new MID_Event;
    memset(track->events, 0, sizeof(MID_Event));
    if (time > 0)
      current->time = time;
    track->event_count++;
    return;
  }

  if (time < 0 || track->events->time > time)
  {
    MID_Event *event = new MID_Event;
    memset(event, 0, sizeof(MID_Event));
    event->next = track->events;
    track->events = current = event;
    track->event_count++;
    return;
  }

  if (!current || current->time > time)
    current = track->events;

  while (current->next)
  {
    if (current->next->time > time)
    {
      MID_Event *event = new MID_Event;
      memset(event, 0, sizeof(MID_Event));

      event->next = current->next;
      current->next = event;
      current = event;
      current->time = time;
      track->event_count++;
      return;
    }

    current = current->next;
  }

  current->next = new MID_Event;
  memset(current->next, 0, sizeof(MID_Event));
  current = current->next;
  current->time = time;

  track->event_count++;
}


unsigned int CXMIDIFile::ConvertListToMTrk(MID_Track *track)
{
  int time = 0;
  int lasttime = 0;
  MID_Event *event;
  unsigned int delta;
  unsigned char last_status = 0;
  unsigned int j;

  // Größe des Tracks ermitteln

  delete[] track->converted;
  track->converted_length = 8;

  for (event = track->events; event; event = event->next)
  {
    if (event->status == 0xFF && event->data[0] == 0x2f)
    {
      lasttime = event->time;
      continue;
    }

    delta = (event->time - time);
    time = event->time;

    track->converted_length += PutVLQ(track, delta, false);

    if ((event->status != last_status) || (event->status >= 0xF0))
      track->converted_length++;

    last_status = event->status;

    switch (event->status >> 4)
    {
      // 2 bytes data
      // Note off, Note on, Aftertouch, Controller and Pitch Wheel
    case 0x8: case 0x9: case 0xA: case 0xB: case 0xE:
      track->converted_length += 2;
      break;

      // 1 bytes data
      // Program Change and Channel Pressure
    case 0xC: case 0xD:
      track->converted_length++;
      break;

      // Variable length
      // SysEx
    case 0xF:
      if (event->status == 0xFF)
        track->converted_length++;

      track->converted_length += PutVLQ(track, event->len, false);

      if (event->len)
      {
        for (j = 0; j < event->len; j++)
          track->converted_length++;
      }
      break;
    }
  }

  // Write out end of stream marker
  if (lasttime > time)
    track->converted_length += PutVLQ(track, lasttime-time, false);
  else
    track->converted_length += PutVLQ(track, 0, false);

  track->converted_length += 2;

  track->converted_length += PutVLQ(track, 0, false);


  // Speicher anlegen
  track->converted = new unsigned char[track->converted_length];
  memset(track->converted, 0, track->converted_length);

  // nun Stream in die das Array schreiben
  unsigned int i = 0;
  time = 0;
  lasttime = 0;
  delta = 0;
  last_status = 0;

  // Header schreiben
  memcpy(&track->converted[i],"MTrk",4);
  i += 4;

  unsigned int length = Endian_Int(track->converted_length);
  memcpy(&track->converted[i], (unsigned char *)&length, 4);
  i += 4;

  for (event = track->events; event; event = event->next)
  {
    if (event->status == 0xFF && event->data[0] == 0x2f)
    {
      lasttime = event->time;
      continue;
    }

    delta = (event->time - time);
    time = event->time;

    i += PutVLQ(track, delta, true, i);

    if ((event->status != last_status) || (event->status >= 0xF0))
      track->converted[i++] = event->status;

    last_status = event->status;

    switch (event->status >> 4)
    {
      // 2 bytes data
      // Note off, Note on, Aftertouch, Controller and Pitch Wheel
    case 0x8: case 0x9: case 0xA: case 0xB: case 0xE:
      track->converted[i++] = event->data[0];
      track->converted[i++] = event->data[1];
      break;

      // 1 bytes data
      // Program Change and Channel Pressure
    case 0xC: case 0xD:
      track->converted[i++] = event->data[0];
      break;

      // Variable length
      // SysEx
    case 0xF:
      if (event->status == 0xFF)
        track->converted[i++] = event->data[0];

      i += PutVLQ(track, event->len, true, i);

      if (event->len)
      {
        for (j = 0; j < event->len; j++)
          track->converted[i++] = event->buffer[j];
      }
      break;
    }
  }

  // Write out end of stream marker
  if (lasttime > time)
    i += PutVLQ(track, lasttime-time, true, i);
  else
    i += PutVLQ(track, 0, true, i);

  track->converted[i++] = 0xFF;
  track->converted[i++] = 0x2F;

  i += PutVLQ(track, 0, true, i);

  if( i != track->converted_length )
  {
    printf("ConvertListToMTrk: WARNING: I've written only %d Bytes instead of %d!",i, track->converted_length);
  }

  return track->converted_length;
}

void CXMIDIFile::ApplyFirstState(MID_Track *track, first_state &fs, int chan_mask)
{
  for (unsigned char channel = 0; channel < 16; channel++)
  {
    MID_Event *patch = fs.patch[channel];
    MID_Event *vol = fs.vol[channel];
    MID_Event *pan = fs.pan[channel];
    MID_Event *bank = fs.bank[channel];
    MID_Event *temp;

    if (!patch || !(chan_mask & 1 << channel))
      continue;

/*#ifdef _DEBUG
    printf("Channel: %d\n", channel+1);
    printf("Patch: %d @ %d\n", patch->data[0], patch->time);

    if(bank)
      printf(" Bank: %d @ %d\n", patch->data[0], patch->time);
    if(vol)
      printf("  Vol: %d @ %d\n", patch->data[0], patch->time);
    if(pan)
      printf("  Pan: %d @ %d\n", patch->data[0], patch->time);
#endif*/


    // Copy Patch Change Event
    temp = patch;
    patch = new MID_Event;
    memset(patch, 0, sizeof(MID_Event));
    patch->time = temp->time;
    patch->status = (unsigned char)(channel|(MIDI_STATUS_PROG_CHANGE << 4));
    patch->data[0] = temp->data[0];

    // Copy Volume
    if (vol && (vol->time > patch->time+PATCH_VOL_PAN_BIAS ||
      vol->time < patch->time-PATCH_VOL_PAN_BIAS))
      vol = NULL;

    temp = vol;
    vol = new MID_Event;
    memset(vol, 0, sizeof(MID_Event));
    vol->status = (unsigned char)(channel|(MIDI_STATUS_CONTROLLER << 4));
    vol->data[0] = 7;

    if (!temp)
      vol->data[1] = VolumeCurve[90];
    else
      vol->data[1] = temp->data[1];


    // Copy Bank
    if (bank && (bank->time > patch->time+PATCH_VOL_PAN_BIAS ||
      bank->time < patch->time-PATCH_VOL_PAN_BIAS))
      bank = NULL;

    temp = bank;

    bank = new MID_Event;
    memset(bank, 0, sizeof(MID_Event));
    bank->status = (unsigned char)(channel|(MIDI_STATUS_CONTROLLER << 4));

    if (!temp)
      bank->data[1] = 0;
    else
      bank->data[1] = temp->data[1];

    // Copy Pan
    if (pan && (pan->time > patch->time+PATCH_VOL_PAN_BIAS ||
      pan->time < patch->time-PATCH_VOL_PAN_BIAS))
      pan = NULL;

    temp = pan;
    pan = new MID_Event;
    memset(pan, 0, sizeof(MID_Event));
    pan->status = (unsigned char)(channel|(MIDI_STATUS_CONTROLLER << 4));
    pan->data[0] = 10;

    if (!temp)
      pan->data[1] = 64;
    else
      pan->data[1] = temp->data[1];

    vol->time = 0;
    pan->time = 0;
    patch->time = 0;
    bank->time = 0;

    bank->next = vol;
    vol->next = pan;
    pan->next = patch;

    patch->next = track->events;

    track->events = bank;
  }
}



XMIDIFile.h

C++:
#ifndef XMIDIFILE_H_
#define XMIDIFILE_H_

#include "helper/endian.h"
#include "midi/GammaTable.h"

#include "structs/structMID_Data.h"
#include "structs/structMID_Track.h"

struct first_state {     // Status,   Data[0]
  MID_Event *patch[16];  // 0xC
  MID_Event *bank[16];   // 0xB,      0
  MID_Event *pan[16];    // 0xB,      7
  MID_Event *vol[16];    // 0xB,      10
};

class CXMIDIFile
{
public:
  CXMIDIFile(MID_Data *data);
  ~CXMIDIFile(void);

  int Convert();

private:
  int ConvertTrackToList(MID_Track *track);
  unsigned int ConvertListToMTrk(MID_Track *track);

  void ApplyFirstState(MID_Track *track, first_state &fs, int chan_mask);

  int ConvertNote(MID_Track *track, const int time, const unsigned char status, const int size);
  int ConvertEvent(MID_Track *track, const int time, const unsigned char status, const int size, first_state &fs);
  int ConvertSystemMessage(MID_Track *track, const int time, const unsigned char status);

  int GetVLQ(MID_Track *track, unsigned int &quant);
  int GetVLQ2(MID_Track *track, unsigned int &quant);
  int PutVLQ(MID_Track *track, unsigned int value, bool write, unsigned int pos = 0);

  void CreateNewEvent(MID_Track *track, int time);

private:
  MID_Data *MIDData;
  MID_Event *current;
  unsigned int position;

  enum {
    MIDI_STATUS_NOTE_OFF    = 0x8,
    MIDI_STATUS_NOTE_ON     = 0x9,
    MIDI_STATUS_AFTERTOUCH  = 0xA,
    MIDI_STATUS_CONTROLLER  = 0xB,
    MIDI_STATUS_PROG_CHANGE = 0xC,
    MIDI_STATUS_PRESSURE    = 0xD,
    MIDI_STATUS_PITCH_WHEEL = 0xE,
    MIDI_STATUS_SYSEX       = 0xF
  };

  bool bank127[16];

  const static char mt32asgm[128];
  static GammaTable<unsigned char> VolumeCurve;
};

#endif // XMIDIFILE_H_



GammaTable.h

C++:
#ifndef GAMMATABLE_H_
#define GAMMATABLE_H_

#include <math.h>

template <class T> class GammaTable
{
private:
   unsigned int size;
   float        sizef;
   T            *table;
   float        gamma;

   // ctor
   GammaTable(){ }

public:
   inline const float & get_gamma ()
   {   return gamma; }

   inline void set_gamma (float g)
   {
      if (g < 0.001f) g = 0.001f;
      if (g == gamma) return;
      gamma = g;

      for (unsigned int i = 0; i < size; i++)
         table[i] = (T) (pow (i / sizef, 1 / gamma) * sizef);
   }

   GammaTable (unsigned int s, float g = 1) : sizef(-1), gamma(-1)
   {
      sizef += size = s>2?s:2;
      table = new T [size];
      set_gamma(g);
   }

   ~GammaTable () { delete [] table; }

   inline const T & operator [] (const T &i) const
   { return table[i]; }
};

#endif // GAMMATABLE_H_




Endian.cpp

C++:
unsigned short Endian_Short(unsigned short x)
{
  // bytes swappen
  return (((x)&0x00ff)<<8) | (((x)&0xff00)>>8);
}

unsigned int Endian_Int(unsigned int x)
{
  // bytes swappen
  return Endian_Short(((x)&0xffff0000)>>16) | Endian_Short((x)&0x0000ffff)<<16;
}


--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
18.11.2005, 17:10 Uhr
xXx
Devil


hmm jetzt raten wir mal alle, wofür das FloSoft geschrieben hat!!! ich weiß es Aber ihr müsst raten!!
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
19.11.2005, 00:17 Uhr
~ddih
Gast


Hi,

vielen dank erstmal für die Antworten, soweit ich weiss kann openal midi Dateien abspielen aber nicht auslesen. Ich werde mal die Klasse von FloSoft ausprobieren vielleicht klappt es ja mit den standard MIDI Dateien. Ich finde es irgendwie seltsam dass es unter Windows so schwierig ist MIDI bibliotheken zu finden wie tse3 unter Linux oder liege ich da falsch ?

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
19.11.2005, 01:15 Uhr
xXx
Devil


hmm du könntest auch einfach FMOD nehemn... ist recht gut...
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
19.11.2005, 09:27 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


da kommste aber wieder nicht explizit an die tracks und co ran, dafür hilft nur manuell auslesen
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
19.11.2005, 09:45 Uhr
Oliver
S2-Pixelgeneral


Man könnte auch das (hardwarenahe) MIDI API von Windows direkt nehmen, da kannste jede Note einzeln abspielen...
--
Demokratie ist die Diktatur der Mehrheit.

www.siedler25.org/ ( Siedler2 - Remake )
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
008
19.11.2005, 13:11 Uhr
~ddih
Gast


Hi,

den Vorschlag von Oliver finde gut, werde mal etwas tiefer in die MIDI API von Windows eintauchen. Vielen dank nochmal für all die Vorschläge
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: