项目作者: Geromatic

项目描述 :
Midi for Unreal Engine
高级语言: C++
项目地址: git://github.com/Geromatic/Midi-Unreal.git
创建时间: 2016-06-20T02:10:21Z
项目社区:https://github.com/Geromatic/Midi-Unreal

开源协议:

下载


Midi-Unreal

Midi for Unreal Engine

Discord: https://discord.gg/yR5wYkX

MarketPlace: https://www.unrealengine.com/marketplace/procedural-midi

Example Project: Updated 2/27/2017

This code provides an interface to read, manipulate, and write MIDI files. “Playback” is supported as a real-time event dispatch system.(Leffelman)

Original Credit goes to Alex Leffelman who created the Android Midi Lib - https://github.com/leffelmania/android-midi-lib
Modified for Unreal Engine: Scott Bishel

http://groundsthirteen.webs.com/midi.htm - libraries for c++/c#/obj-c

Features:

  • Ability to import [drag & drop] Midi files in Unreal
  • Load/Play Midi
  • Built in Midi Device Interface
  • Choice between MIDI output device (ex. computer, synthesizer, etc) or generated audio playback [**]
  • Ability to connect external MIDI input device (ex. Midi Keyboard, Midi Fighter 64, any MIDI-equipped hardware) [**]

[Sending MIDI to/from another program or VST] is possible with a virtual MIDI driver.
LoopMidi


—By sending midi data to the virtual midi device…you can have other apps be able to retrieve that data


-You can interact with the midi device by using the Midi Interface Component

** [Shown in Demo Project on marketplace]

Plugin Build Supports:

  • Windows(32/64): [Packaged+Tested+Works]
  • HTML5: [Packaged+Tested+Works]
  • Android(All): [Packaged+Tested+Works]
  • Linus: [Packaged+Tested+Works]
  • Mac/IOS: [Packaged+Tested+Works]

Installation [Github Version Only / C++ Project Required]

[Caution: careful when you have marketplace and c++ plugins on same UE version as they may conflict with eachother]

Place MidiAsset folder in your Plugins folder in youe Unreal project

Showcase: [Blueprint]

ScreenShot
ScreenShot
ScreenShot
ScreenShot
ScreenShot

Example Usage: [Beta-Untested/C++]


  1. // headers
  2. #include <vector> // std::vector
  3. #include <iostream> // std::cout, std::ostream, std::ios, std::streambuf
  4. #include <fstream> // std::filebuf
  5. using namespace std; // optional

Reading and Writing a MIDI file:

  1. struct membuf : std::streambuf
  2. {
  3. membuf(char* begin, char* end) {
  4. this->setg(begin, begin, end);
  5. }
  6. };
  7. FString path;
  8. TArray<uint8> data;
  9. bool result = FFileHelper::LoadFileToArray(data, path.GetCharArray().GetData());
  10. if (result == 0 || data.Num() == 0)
  11. return;
  12. char* ptr = (char*)data.GetData();
  13. membuf sbuf(ptr, ptr + data.Num());
  14. std::istream in(&sbuf);
  15. MidiFile midi(in);
  16. ...
  17. std::filebuf fb;
  18. fb.open("test.txt", std::ios::out);
  19. std::ostream os(&fb);
  20. midi.writeToFile(os);

Manipulating a MIDI file’s data:

Removing a track:

  1. midi.removeTrack(2);

Removing any event that is not a note from track 1:

  1. MidiTrack& track = *midi.getTracks()[1];
  2. std::vector<MidiEvent*>::iterator it = track.getEvents().begin();
  3. std::vector<MidiEvent*> eventsToRemove;
  4. while (it)
  5. {
  6. MidiEvent* _event = *it;
  7. if (!(_event->getType() == ChannelEvent::NOTE_ON) && !(_event->getType() == ChannelEvent::NOTE_OFF))
  8. {
  9. eventsToRemove.Add(_event);
  10. }
  11. it++;
  12. }
  13. for (int i = 0; i < eventsToRemove.Num(); i++) {
  14. track.removeEvent(eventsToRemove[i]);
  15. }

Reducing the tempo by half:

  1. MidiTrack& track = *midi.getTracks()[0];
  2. std::vector<MidiEvent*>::iterator it = track.getEvents().begin();
  3. while (it)
  4. {
  5. MidiEvent* _event = *it;
  6. if (_event->getType() == MetaEvent::TEMPO)
  7. {
  8. Tempo* tempoEvent = (Tempo*)_event;
  9. tempoEvent->setBpm(tempoEvent->getBpm() / 2);
  10. }
  11. it++;
  12. }

Composing a new MIDI file:

  1. // 1. Create some MidiTracks
  2. MidiTrack& tempoTrack = *new MidiTrack();
  3. MidiTrack& noteTrack = *new MidiTrack();
  4. // 2. Add events to the tracks
  5. // Track 0 is the tempo map
  6. TimeSignature& ts = *new TimeSignature();
  7. ts.setTimeSignature(4, 4, TimeSignature::DEFAULT_METER, TimeSignature::DEFAULT_DIVISION);
  8. Tempo& tempo = *new Tempo();
  9. tempo.setBpm(228);
  10. tempoTrack.insertEvent(&ts);
  11. tempoTrack.insertEvent(&tempo);
  12. // Track 1 will have some notes in it
  13. const int NOTE_COUNT = 80;
  14. for(int i = 0; i < NOTE_COUNT; i++)
  15. {
  16. int channel = 0;
  17. int pitch = 1 + i;
  18. int velocity = 100;
  19. long tick = i * 480;
  20. long duration = 120;
  21. noteTrack.insertNote(channel, pitch, velocity, tick, duration);
  22. }
  23. // 3. Create a MidiFile with the tracks we created
  24. std::vector<MidiTrack*>& tracks = *new std::vector<MidiTrack*>();
  25. tracks.push_back(&tempoTrack);
  26. tracks.push_backeTrack);
  27. MidiFile& midi = *new MidiFile(MidiFile::DEFAULT_RESOLUTION, tracks);
  28. // 4. Write the MIDI data to a file
  29. std::filebuf fb;
  30. fb.open("test.txt", std::ios::out);
  31. std::ostream os(&fb);
  32. midi.writeToFile(os);

Listening for and processing MIDI events

  1. // Create a new MidiProcessor:
  2. MidiProcessor processor;
  3. processor.load(midi);
  4. // Register for the events you're interested in:
  5. EventPrinter ep;
  6. processor.setListener(&ep);
  7. // Start the processor:
  8. processor.start();
  1. // This class will print any event it receives to the console
  2. class EventPrinter: public MidiEventListener
  3. {
  4. public:
  5. EventPrinter()
  6. {
  7. }
  8. void onStart(bool fromBeginning)
  9. {
  10. if(fromBeginning)
  11. {
  12. UE_LOG(LogTemp, Display, TEXT("Started!"));
  13. }
  14. else
  15. {
  16. UE_LOG(LogTemp, Display, TEXT("Resumed!"));
  17. }
  18. }
  19. void onEvent(MidiEvent* _event, long ms, int trackID)
  20. {
  21. FString layerName(_event->toString().c_str());
  22. UE_LOG(LogTemp, Display, TEXT("received event: %s"), *layerName);
  23. }
  24. void onStop(bool finished)
  25. {
  26. if(finished)
  27. {
  28. UE_LOG(LogTemp, Display, TEXT("Finished!"));
  29. }
  30. else
  31. {
  32. UE_LOG(LogTemp, Display, TEXT("Paused!"));
  33. }
  34. }
  35. };