Created
March 23, 2023 21:55
-
-
Save sfpgmr/50d6d7c6fed7ceac2330b1ac60237174 to your computer and use it in GitHub Desktop.
chatgptに作ってもらったピアノロールエディタのコード(動きません)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <imgui.h> | |
#include <fstream> | |
#include <iostream> | |
#include <sstream> | |
#include <algorithm> | |
#include <vector> | |
struct NoteData { | |
int pitch; | |
float start; | |
float length; | |
}; | |
class PianoRollEditor { | |
public: | |
PianoRollEditor() : gridDivision(16), gridSubdivision(4), noteBeingEdited(-1) {} | |
void Render() { | |
ImGui::Begin("Piano Roll Editor"); | |
DrawGrid(); | |
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { | |
// 新しいノートを追加する | |
ImVec2 mousePos = ImGui::GetMousePos(); | |
int pitch = (int)(127 - (mousePos.y - ImGui::GetCursorScreenPos().y) / gridYSize); | |
float start = (mousePos.x - ImGui::GetCursorScreenPos().x) / gridXSize; | |
noteBeingEdited = AddNote(pitch, start, 0.0f); | |
} | |
if (noteBeingEdited >= 0) { | |
// ノートを編集中の場合 | |
bool noteDragged = ImGui::IsMouseDragging(ImGuiMouseButton_Left); | |
bool noteReleased = ImGui::IsMouseReleased(ImGuiMouseButton_Left); | |
if (noteDragged) { | |
// ノートをドラッグ中の場合 | |
ImVec2 mousePos = ImGui::GetMousePos(); | |
float start = (mousePos.x - ImGui::GetCursorScreenPos().x) / gridXSize; | |
float length = std::max < float>(start - notes[noteBeingEdited].start, 0.0f); | |
notes[noteBeingEdited].length = length; | |
} | |
else if (noteReleased) { | |
// ノートがリリースされた場合 | |
ImVec2 mousePos = ImGui::GetMousePos(); | |
float start = (mousePos.x - ImGui::GetCursorScreenPos().x) / gridXSize; | |
float length = std::max<float>(start - notes[noteBeingEdited].start, 0.0f); | |
notes[noteBeingEdited].length = length; | |
noteBeingEdited = -1; | |
} | |
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Delete))) { | |
// Deleteキーが押された場合 | |
notes.erase(notes.begin() + noteBeingEdited); | |
noteBeingEdited = -1; | |
} | |
} | |
for (int i = 0; i < notes.size(); i++) { | |
// ノートを描画する | |
ImVec2 notePos = ImVec2(notes[i].start * gridXSize, (127 - notes[i].pitch) * gridYSize + ImGui::GetCursorScreenPos().y); | |
ImVec2 noteSize = ImVec2(notes[i].length * gridXSize, gridYSize); | |
ImU32 noteColor = (i == noteBeingEdited) ? IM_COL32(255, 0, 0, 255) : IM_COL32(255, 255, 255, 255); | |
ImGui::GetWindowDrawList()->AddRectFilled(notePos, ImVec2(notePos.x + noteSize.x, notePos.y + noteSize.y), noteColor); | |
} | |
ImGui::End(); | |
// MIDIファイルをエクスポートする | |
if (ImGui::Button("Export MIDI")) { | |
ExportMIDI("output.mid"); | |
} | |
} | |
private: | |
int gridDivision; | |
int gridSubdivision; | |
std::vector<NoteData> notes; | |
int noteBeingEdited; | |
float gridXSize; | |
float gridYSize; | |
void DrawGrid() { | |
ImDrawList* drawList = ImGui::GetWindowDrawList(); | |
ImVec2 cursorPos = ImGui::GetCursorScreenPos(); | |
ImVec2 windowPos = ImGui::GetWindowPos(); | |
ImVec2 windowSize = ImGui::GetWindowSize(); | |
float totalWidth = windowSize.x - 16.0f; | |
float totalHeight = windowSize.y - 16.0f; | |
// グリッドの大きさを計算する | |
gridXSize = totalWidth / (gridDivision * gridSubdivision); | |
gridYSize = totalHeight / 128.0f; | |
// グリッドを描画する | |
drawList->PushClipRect(ImVec2(windowPos.x + 8, windowPos.y + 8), ImVec2(windowPos.x + 8 + totalWidth, windowPos.y + 8 + totalHeight)); | |
for (int i = 0; i <= gridDivision * gridSubdivision; i++) { | |
float x = i * gridXSize; | |
drawList->AddLine(ImVec2(cursorPos.x + x, cursorPos.y), ImVec2(cursorPos.x + x, cursorPos.y + totalHeight), IM_COL32(255, 255, 255, 255)); | |
} | |
for (int i = 0; i <= 127; i++) { | |
float y = i * gridYSize; | |
drawList->AddLine(ImVec2(cursorPos.x, cursorPos.y + y), ImVec2(cursorPos.x + totalWidth, cursorPos.y + y), IM_COL32(255, 255, 255, 255)); | |
} | |
drawList->PopClipRect(); | |
} | |
int AddNote(int pitch, float start, float length) { | |
notes.push_back({ pitch, start, length }); | |
return notes.size() - 1; | |
} | |
void ExportMIDI(const std::string& filename) { | |
std::ofstream file(filename, std::ios::binary); | |
if (!file.is_open()) { | |
std::cout << "Failed to open file for writing: " << filename << std::endl; | |
return; | |
} | |
// MIDIファイルヘッダーを書き込む | |
file.write("MThd", 4); | |
uint32_t headerLength = 6; | |
file.write((const char*)&headerLength, 4); | |
uint16_t format = 1; | |
file.write((const char*)&format, 2); | |
uint16_t numTracks = 1; | |
file.write((const char*)&numTracks, 2); | |
uint16_t timeDivision = 480; | |
file.write((const char*)&timeDivision, 2); | |
// MIDIトラックヘッダーを書き込む | |
file.write("MTrk", 4); | |
uint32_t trackLength = 0; | |
file.write((const char*)&trackLength, 4); | |
// MIDIイベントを書き込む | |
for (const NoteData& note : notes) { | |
// NoteData// 開始イベント | |
uint8_t statusByte = 0x90; // NoteData On | |
uint8_t pitch = note.pitch; | |
uint8_t velocity = 100; | |
uint8_t deltaTimeBytes[4]; | |
uint32_t deltaTime = (uint32_t)(note.start * timeDivision); | |
EncodeDeltaTime(deltaTimeBytes, deltaTime); | |
file.write((const char*)deltaTimeBytes, 4); | |
file.write((const char*)&statusByte, 1); | |
file.write((const char*)&pitch, 1); | |
file.write((const char*)&velocity, 1); | |
// 終了イベント | |
statusByte = 0x80; // NoteData Off | |
deltaTime = (uint32_t)((note.start + note.length) * timeDivision) - deltaTime; | |
EncodeDeltaTime(deltaTimeBytes, deltaTime); | |
file.write((const char*)deltaTimeBytes, 4); | |
file.write((const char*)&statusByte, 1); | |
file.write((const char*)&pitch, 1); | |
file.write((const char*)&velocity, 1); | |
} | |
// MIDIトラックの長さを書き込む | |
trackLength = (uint32_t)file.tellp() - 8; | |
file.seekp(8); | |
file.write((const char*)&trackLength, 4); | |
std::cout << "MIDI file exported to " << filename << std::endl; | |
} | |
void EncodeDeltaTime(uint8_t* bytes, uint32_t deltaTime) { | |
int i = 3; | |
while (deltaTime > 0) { | |
bytes[i] = deltaTime & 0x7F; | |
deltaTime >>= 7; | |
if (i != 3) { | |
bytes[i] |= 0x80; | |
} | |
i--; | |
} | |
} | |
}; | |
int main() { | |
PianoRollEditor editor; | |
editor.Run(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment