Created
March 23, 2023 22:50
-
-
Save sfpgmr/b00433b4e0f04fc4ad5284b8414e8472 to your computer and use it in GitHub Desktop.
chatgptにおしえてもらったimguiを使用したピアノロールエディタのコード(動きません)
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 "mainWindow.h" | |
#include <regex> | |
//using namespace ImGui; | |
using namespace sf; | |
/* | |
#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; | |
} | |
*/ | |
/* | |
// MIDIノートの情報を格納する構造体 | |
struct NoteInfo { | |
int pitch; // MIDIノート番号 | |
int startTick; // 開始タイミング | |
int endTick; // 終了タイミング | |
}; | |
// ピアノロールの縦方向のキー数 | |
const int NUM_KEYS = 88; | |
// ピアノロールの横方向のティック数 | |
const int NUM_TICKS = 480; | |
// ピアノロールのキーの高さを返す関数 | |
float GetKeyHeight() { | |
return ImGui::GetContentRegionAvail().y / NUM_KEYS; | |
} | |
// ピアノロールのティックの幅を返す関数 | |
float GetTickWidth() { | |
return ImGui::GetContentRegionAvail().x / NUM_TICKS; | |
} | |
// ピアノロールのUIを描画する関数 | |
void MainWindow::drawPianoroll(int32_t songIndex) { | |
// サンプルコードのメイン関数 | |
std::vector<NoteInfo> notes = { | |
{60, 0, 240}, | |
{64, 120, 360}, | |
{67, 240, 480} | |
}; | |
// ピアノロールの上部にキー番号を表示 | |
for (int key = NUM_KEYS - 1; key >= 0; key--) { | |
ImGui::Text("%d", key + 1); | |
ImGui::SameLine(); | |
} | |
// ピアノロールの左側にティック数を表示 | |
for (int tick = 0; tick < NUM_TICKS; tick += 24) { | |
ImGui::Text("%d", tick); | |
ImGui::SameLine(); | |
} | |
// ピアノロールの本体を描画 | |
for (int key = NUM_KEYS - 1; key >= 0; key--) { | |
ImGui::BeginGroup(); | |
// キーの背景を描画 | |
ImGui::PushID(getId()); | |
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.9f, 0.9f, 0.9f, 1.0f)); | |
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.8f, 0.8f, 0.8f, 1.0f)); | |
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.7f, 0.7f, 0.7f, 1.0f)); | |
ImGui::Button("", ImVec2(ImGui::GetContentRegionAvail().x, GetKeyHeight())); | |
ImGui::PopStyleColor(3); | |
ImGui::PopID(); | |
// MIDIノートがある場合はノートの範囲を描画 | |
for (const auto& note : notes) { | |
if (note.pitch == key) { | |
const float x1 = note.startTick * GetTickWidth(); | |
const float x2 = note.endTick * GetTickWidth(); | |
ImGui::PushID(getId()); | |
ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0.7f, 0.7f, 0.9f, 1.0f)); | |
ImGui::PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0.6f, 0.6f, 0.8f, 1.0f)); | |
ImGui::PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0.5f, 0.5f, 0.7f, 1.0f)); | |
ImGui::Button("", ImVec2(x2 - x1, GetKeyHeight())); | |
ImGui::PopStyleColor(3); | |
ImGui::PopID(); | |
} | |
} | |
ImGui::EndGroup(); | |
} | |
//auto& io = ImGui::GetIO(); | |
//auto& songs{ audioManager.getSongs() }; | |
//SongPtr song{ songs[songIndex] }; | |
//auto& tracks{ song->getTracks() }; | |
//TrackEditInfos& trackEditInfos{ trackEditInfosList[songIndex] }; | |
} | |
*/ | |
#include <vector> | |
#include <algorithm> | |
#include <string> | |
#include <iostream> | |
#include <glad/glad.h> | |
#include <GLFW/glfw3.h> | |
#include <imgui.h> | |
#include <imgui_impl_glfw.h> | |
#include <imgui_impl_opengl3.h> | |
struct NoteInfo { | |
int pitch; // MIDIノートの音高 (0~127) | |
int start_tick; // MIDIノートの開始ティック | |
int end_tick; // MIDIノートの終了ティック | |
// MIDIノートの長さを返す | |
int length() const { | |
return end_tick - start_tick; | |
} | |
}; | |
class PianoRoll { | |
public: | |
// コンストラクタ | |
PianoRoll() { | |
// キーボードの音名 | |
keyboard_names_ = { | |
"C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B" | |
}; | |
} | |
// デストラクタ | |
~PianoRoll() {} | |
// MIDIノートの情報を設定 | |
void set_notes(const std::vector<NoteInfo>& notes) { | |
notes_ = notes; | |
} | |
// MIDIノートの情報を取得 | |
std::vector<NoteInfo> get_notes() const { | |
return notes_; | |
} | |
// ピアノロールのUIを描画 | |
void draw() { | |
// ピアノロールのウィンドウを作成 | |
ImGui::Begin("Piano Roll"); | |
// メニューバーを表示 | |
draw_menu_bar(); | |
// キーボードの背景を表示 | |
draw_keyboard_background(); | |
// MIDIノートを表示 | |
draw_notes(); | |
// MIDIノートのドラッグ&ドロップを処理 | |
process_drag_drop(); | |
// ピアノロールのスクロールを処理 | |
process_scroll(); | |
ImGui::End(); | |
} | |
private: | |
std::vector<NoteInfo> notes_; // MIDIノートの情報 | |
std::vector<std::string> keyboard_names_; // キーボードの音名 | |
int current_note_index_ = -1; // 現在選択されているMIDIノートのインデックス | |
bool is_dragging_note_ = false; // MIDIノートをドラッグ中かどうか | |
bool is_resizing_note_ = false; // MIDIノートをリサイズ中かどうか | |
bool is_cutting_note_ = false; | |
// カット操作中かどうか | |
bool is_copying_ = false; // コピー操作中かどうか | |
bool is_pasting_ = false; // ペースト操作中かどうか | |
int copy_note_index_ = -1; // コピーされたMIDIノートのインデックス | |
int paste_start_tick_ = -1; // ペーストする開始ティック | |
int paste_end_tick_ = -1; // ペーストする終了ティック | |
bool is_scroll_active_ = false; // スクロール中かどうか | |
ImVec2 scroll_ = ImVec2(0.0f, 0.0f); // スクロールのオフセット | |
float scroll_speed_ = 10.0f; // スクロール速度 | |
float note_width_ = 20.0f; // MIDIノートの横幅 | |
float note_height_ = 10.0f; // MIDIノートの縦幅 | |
float note_min_length_ = 5.0f; // MIDIノートの最小長さ | |
float note_drag_threshold_ = 5.0f; // MIDIノートをドラッグするための閾値 | |
ImVec2 note_resize_direction_ = ImVec2(0.0f, 0.0f); // MIDIノートのリサイズ方向 | |
ImVec2 cut_start_pos_ = ImVec2(0.0f, 0.0f); // カット操作の開始位置 | |
ImVec2 cut_end_pos_ = ImVec2(0.0f, 0.0f); // カット操作の終了位置 | |
// メニューバーを表示 | |
void draw_menu_bar() { | |
if (ImGui::BeginMenuBar()) { | |
if (ImGui::BeginMenu("File")) { | |
if (ImGui::MenuItem("Open MIDI")) { | |
// MIDIファイルを開く処理を記述 | |
} | |
if (ImGui::MenuItem("Save MIDI")) { | |
// MIDIファイルを保存する処理を記述 | |
} | |
ImGui::EndMenu(); | |
} | |
ImGui::EndMenuBar(); | |
} | |
} | |
// キーボードの背景を表示 | |
void draw_keyboard_background() { | |
ImGuiStyle& style = ImGui::GetStyle(); | |
ImDrawList* draw_list = ImGui::GetWindowDrawList(); | |
ImVec2 pos = ImGui::GetCursorScreenPos(); | |
ImVec2 size = ImGui::GetContentRegionAvail(); | |
float white_key_width = size.x / 12.0f; | |
float black_key_width = white_key_width * 0.6f; | |
float white_key_height = size.y; | |
float black_key_height = white_key_height * 0.6f; | |
for (int i = 0; i < 12; i++) { | |
if (i % 12 == 0 || i % 12 == 2 || i % 12 == 4 || i % 12 == 5 || i % 12 == 7 || i % 12 == 9 || i % 12 == 11) { | |
// 白鍵盤の描画 | |
draw_list->AddRectFilled(pos, ImVec2(pos.x + white_key_width, pos | |
// 黒鍵盤の描画 | |
draw_list->AddRectFilled(ImVec2(pos.x + white_key_width - black_key_width / 2.0f, pos.y), ImVec2(pos.x + white_key_width + black_key_width / 2.0f, pos.y + black_key_height), IM_COL32_BLACK); | |
} | |
pos.x += white_key_width; | |
} | |
} | |
// MIDIノートを表示 | |
void draw_notes() { | |
ImDrawList* draw_list = ImGui::GetWindowDrawList(); | |
ImVec2 pos = ImGui::GetCursorScreenPos(); | |
for (int i = 0; i < notes_.size(); i++) { | |
MidiNote& note = notes_[i]; | |
if (note.start_tick + note_length(note) < scroll_start_tick_ || note.start_tick > scroll_end_tick_) { | |
continue; | |
} | |
ImVec2 note_pos = pos + ImVec2((note.start_tick - scroll_start_tick_) * note_width_, (12 - note.note_number) * note_height_); | |
ImVec2 note_size = ImVec2(note_length(note) * note_width_, note_height_); | |
ImU32 note_color = note_color(note.note_number); | |
draw_list->AddRectFilled(note_pos, note_pos + note_size, note_color, 2.0f); | |
if (ImGui::IsMouseHoveringRect(note_pos, note_pos + note_size)) { | |
// MIDIノートをドラッグ中の場合 | |
if (ImGui::IsMouseDragging(0) && !is_copying_ && !is_pasting_ && !is_resize_active_) { | |
if (note_resize_direction_.x != 0.0f) { | |
// MIDIノートをリサイズする | |
int new_length = (int)((ImGui::GetMousePos().x - note_pos.x) / note_width_ + 0.5f); | |
if (new_length < note_min_length_) { | |
new_length = note_min_length_; | |
} | |
note.length = new_length; | |
} | |
else { | |
// MIDIノートをドラッグする | |
int delta_tick = (int)((ImGui::GetMousePos().x - prev_mouse_pos_.x) / note_width_ + 0.5f); | |
note.start_tick += delta_tick; | |
if (note.start_tick < 0) { | |
note.start_tick = 0; | |
} | |
} | |
} | |
else { | |
// MIDIノートのリサイズ方向を決定 | |
ImVec2 mouse_pos = ImGui::GetMousePos(); | |
note_resize_direction_ = ImVec2(mouse_pos.x >= note_pos.x + note_size.x - note_drag_threshold_ ? 1.0f : mouse_pos.x <= note_pos.x + note_drag_threshold_ ? -1.0f : 0.0f, mouse_pos.y >= note_pos.y + note_size.y - note_drag_threshold_ ? 1.0f : mouse_pos.y <= note_pos.y + note_drag_threshold_ ? -1.0f : 0.0f); | |
if (note_resize_direction_.x != 0.0f || note_resize_direction_.y != 0.0f) { | |
is_resize_active_ = true; | |
} | |
} | |
} | |
else if (ImGui::IsMouseClicked(0) && !is_copying_ && !is_pasting_ && !is_resize_active_) { | |
// MIDIノートを選択する | |
if (ImGui::IsMouseHoveringRect(note_pos, note_pos + note_size)) { | |
selected_note_index_ | |
= i; | |
prev_mouse_pos_ = ImGui::GetMousePos(); | |
note_resize_direction_ = ImVec2(0.0f, 0.0f); | |
is_resize_active_ = false; | |
} | |
} | |
} | |
// MIDIノートをドラッグ中の場合 | |
if (selected_note_index_ >= 0 && ImGui::IsMouseDragging(0) && !is_copying_ && !is_pasting_ && !is_resize_active_) { | |
MidiNote& note = notes_[selected_note_index_]; | |
int delta_tick = (int)((ImGui::GetMousePos().x - prev_mouse_pos_.x) / note_width_ + 0.5f); | |
note.start_tick += delta_tick; | |
if (note.start_tick < 0) { | |
note.start_tick = 0; | |
} | |
prev_mouse_pos_ = ImGui::GetMousePos(); | |
} | |
// MIDIノートのリサイズを終了する | |
if (ImGui::IsMouseReleased(0) && is_resize_active_) { | |
note_resize_direction_ = ImVec2(0.0f, 0.0f); | |
is_resize_active_ = false; | |
} | |
} | |
// MIDIノートを追加 | |
void add_note() { | |
MidiNote note; | |
note.note_number = 60; | |
note.velocity = 127; | |
note.start_tick = (int)(scroll_start_tick_ + (ImGui::GetMousePos().x - ImGui::GetCursorScreenPos().x) / note_width_ + 0.5f); | |
note.length = note_min_length_; | |
notes_.push_back(note); | |
selected_note_index_ = (int)notes_.size() - 1; | |
is_copying_ = false; | |
is_pasting_ = false; | |
} | |
// MIDIノートを削除 | |
void delete_note() { | |
if (selected_note_index_ >= 0) { | |
notes_.erase(notes_.begin() + selected_note_index_); | |
selected_note_index_ = -1; | |
is_copying_ = false; | |
is_pasting_ = false; | |
} | |
} | |
// MIDIノートのコピー | |
void copy_note() { | |
if (selected_note_index_ >= 0) { | |
copy_note_ = notes_[selected_note_index_]; | |
is_copying_ = true; | |
is_pasting_ = false; | |
} | |
} | |
// MIDIノートの貼り付け | |
void paste_note() { | |
if (is_copying_) { | |
MidiNote note = copy_note_; | |
note.start_tick = (int)(scroll_start_tick_ + (ImGui::GetMousePos().x - ImGui::GetCursorScreenPos().x) / note_width_ + 0.5f); | |
notes_.push_back(note); | |
selected_note_index_ = (int)notes_.size() - 1; | |
is_copying_ = false; | |
is_pasting_ = true; | |
} | |
} | |
// MIDIノートの移動 | |
void move_note(int delta_tick) { | |
if (selected_note_index_ >= 0) { | |
MidiNote& note = notes_[selected_note_index_]; | |
note.start_tick += delta_tick; | |
if (note.start_tick < 0) { | |
note.start_tick = 0; | |
} | |
} | |
} | |
// MIDIノートの長さを取得 | |
int note_length(const MidiNote& note) { | |
return note.length == 0 ? note_min_length_ : note.length; | |
} | |
// MIDIノート | |
// MIDIノートを描画 | |
void draw_notes() { | |
ImDrawList* draw_list = ImGui::GetWindowDrawList(); | |
ImVec2 cursor_pos = ImGui::GetCursorScreenPos(); | |
ImVec2 canvas_pos = ImGui::GetCursorScreenPos() + ImVec2(0.0f, header_height_); | |
ImVec2 canvas_size = ImGui::GetContentRegionAvail(); | |
canvas_size.x -= vertical_scrollbar_width_; | |
canvas_size.y -= horizontal_scrollbar_height_; | |
int num_notes = (int)notes_.size(); | |
int num_octaves = 7; | |
int num_pitches = num_octaves * 12; | |
int octave_offset = 4; | |
int pitch_offset = octave_offset * 12 - num_pitches / 2; | |
int num_grid_lines = (int)(canvas_size.x / note_width_) + 1; | |
float note_height = canvas_size.y / num_pitches; | |
float note_start_y = canvas_pos.y + note_height * (num_pitches - pitch_offset); | |
float note_end_y = canvas_pos.y + note_height * (num_pitches - pitch_offset - num_pitches); | |
float grid_start_x = canvas_pos.x + note_width_ - fmod(scroll_start_tick_ * note_width_, note_width_); | |
float grid_start_tick = (int)(scroll_start_tick_ / note_min_length_) * note_min_length_; | |
for (int i = 0; i < num_notes; i++) { | |
const MidiNote& note = notes_[i]; | |
if (note.start_tick + note_length(note) >= scroll_start_tick_ && note.start_tick <= scroll_end_tick_) { | |
float note_x = canvas_pos.x + note.start_tick * note_width_ - scroll_start_tick_ * note_width_; | |
float note_y = note_start_y - note_height * (note.note_number - pitch_offset + 1) + note_height * note_resize_direction_.y; | |
ImVec2 note_pos(note_x, note_y); | |
ImVec2 note_size(note_length(note) * note_width_, note_height); | |
bool is_selected = selected_note_index_ == i; | |
bool is_resizable = ImGui::IsMouseHoveringRect(note_pos, note_pos + note_size) && fabsf(note_pos.y + note_size.y - ImGui::GetMousePos().y) < note_resize_threshold_; | |
if (is_selected) { | |
draw_list->AddRectFilled(note_pos - ImVec2(2.0f, 2.0f), note_pos + note_size + ImVec2(2.0f, 2.0f), note_color_selected_, 4.0f); | |
} | |
else { | |
draw_list->AddRectFilled(note_pos, note_pos + note_size, note_color_, 4.0f); | |
} | |
if (is_resizable) { | |
draw_list->AddRectFilled(ImVec2(note_pos.x + note_size.x - note_resize_handle_size_ / 2, note_pos.y + note_size.y - note_resize_handle_size_ / 2), | |
ImVec2(note_pos.x + note_size.x + note_resize_handle_size_ / 2, note_pos.y + note_size.y + note_resize_handle_size_ / 2), | |
note_color_resizable_); | |
} | |
} | |
} | |
// グリッドを描画 | |
for (int i = 0; i < num_grid_lines; i++) { | |
float grid_x = grid_start_x + i * note_width_; | |
float grid_tick = grid_start_tick + i * note_min_length_; | |
if (i % 4 == 0) { | |
draw_list->AddLine(ImVec2(grid_x, canvas_pos.y), ImVec2(grid_x, canvas_pos.y + canvas_size.y), grid_color_strong_); | |
} | |
else { | |
draw_list->AddLine(ImVec2(grid_x, canvas_pos.y), ImVec2(grid_x, canvas_pos.y + canvas_size.y), grid_color_weak_); | |
} | |
char label[32]; | |
sprintf(label, "%.0f", grid_tick); | |
draw_list->AddText(ImVec2(grid_x + 4.0f, canvas_pos.y), text_color_, label); | |
} | |
// ノート名を描画 | |
for (int i = 0; i < num_pitches; i++) { | |
char note_name[4]; | |
int note_number = i + pitch_offset; | |
int octave = note_number / 12; | |
int pitch = note_number % 12; | |
sprintf(note_name, "%c%d", note_names_[pitch], octave); | |
float note_name_y = note_start_y - note_height * (i + 1) + note_height / 2.0f - text_size_ / 2.0f; | |
draw_list->AddText(ImVec2(canvas_pos.x, note_name_y), text_color_, note_name); | |
} | |
// ラバーバンドを描画 | |
if (drag_mode_ == DragMode::Selecting) { | |
draw_list->AddRectFilled(drag_start_, drag_end_, rubber_band_color_, 0.0f); | |
} | |
} | |
// MIDIファイルをロード | |
void load_midi_file(const char* path) { | |
// MIDIファイルを解析 | |
midifile_.read(path); | |
// トラック数をカウント | |
int num_tracks = 0; | |
for (int i = 0; i < midifile_.size(); i++) { | |
if (!midifile_[i].empty()) { | |
num_tracks++; | |
} | |
} | |
if (num_tracks == 0) { | |
return; | |
} | |
// ノートリストを初期化 | |
notes_.clear(); | |
// トラックを解析 | |
for (int i = 0; i < midifile_.size(); i++) { | |
if (midifile_[i].empty()) { | |
continue; | |
} | |
for (int j = 0; j < midifile_[i].size(); j++) { | |
MidiEvent& event = midifile_[i][j]; | |
if (event.isNoteOn()) { | |
MidiNote note; | |
note.track = i; | |
note.channel = event.getChannel(); | |
note.start_tick = event.tick; | |
note.note_number = event.getNoteNumber(); | |
note.velocity = event.getVelocity(); | |
for (int k = j + 1; k < midifile_[i].size(); k++) { | |
MidiEvent& event2 = midifile_[i][k]; | |
if (event2.isNoteOff() && event2.getChannel() == note.channel && event2.getNoteNumber() == note.note_number) { | |
note.end_tick = event2.tick; | |
break; | |
} | |
} | |
if (note.end_tick == -1) { | |
note.end_tick = midifile_.getEndTick(); | |
} | |
notes_.push_back(note); | |
} | |
} | |
} | |
// ノートリストをソート | |
std::sort(notes_.begin(), notes_.end(), [](const MidiNote& a, const MidiNote& b) { return a.start_tick < b.start_tick; }); | |
// メタ情報を取得 | |
tempo_map_.clear(); | |
time_sig_map_.clear(); | |
for (int i = 0; i < midifile_[0].size(); i++) { | |
MidiEvent& event = midifile_[0][i]; | |
if (event.isTempo()) { | |
float tempo = 60000000.0f / event.getTempoBPM(); | |
tempo_map_[event.tick] = tempo; | |
} | |
else if (event.isTimeSignature()) { | |
TimeSignature time_sig; | |
time_sig.numerator = event.getTimeSignatureNumerator(); | |
time_sig.denominator = pow(2, event.getTimeSignatureDenominator()); | |
time_sig_map_[event.tick] = time_sig; | |
} | |
} | |
// キーボードをリセット | |
pitch_offset_ = 0; | |
// ビューポートをリセット | |
view_offset_ = 0.0f; | |
view_scale_ = 1.0f; | |
} | |
// MIDIファイルを保存 | |
void save_midi_file(const char* path) { | |
// MIDIファイルを生成 | |
MidiFile midi_file; | |
midi_file.setTicksPerQuarter(midifile_.getTicksPerQuarter()); | |
// トラックを生成 | |
std::vector<int> note_index(notes_.size()); | |
std::iota(note_index.begin(), note_index.end(), 0); | |
std::sort(note_index.begin(), note_index.end(), [&](int a, int b) { return notes_[a].start_tick < notes_[b].start_tick; }); | |
std::vector<int> track_index(note_index.size()); | |
std::iota(track_index.begin(), track_index.end(), 0); | |
std::sort(track_index.begin(), track_index.end(), [&](int a, int b) { return notes_[note_index[a]].track < notes_[note_index[b]].track; }); | |
std::vector<std::vector<MidiEvent>> tracks; | |
for (int i = 0; i < num_tracks_; i++) { | |
tracks.push_back(std::vector<MidiEvent>()); | |
} | |
for (int i = 0; i < note_index.size(); i++) { | |
int note_i = note_index[i]; | |
int track_i = track_index[i]; | |
MidiNote& note = notes_[note_i]; | |
int prev_track_i = (i == 0) ? -1 : track_index[i - 1]; | |
if (note.track != prev_track_i) { | |
// トラックを変更 | |
tracks[note.track].push_back(MidiEvent::makeTrackNameEvent(track_names_[note.track].c_str())); | |
tracks[note.track].push_back(MidiEvent::makeProgramChangeEvent(note.channel, program_nums_[note.track])); | |
} | |
// ノートオンイベントを追加 | |
MidiEvent note_on_event = MidiEvent::makeNoteOnEvent(note.channel, note.note_number, note.velocity, note.start_tick); | |
tracks[note.track].push_back(note_on_event); | |
// ノートオフイベントを追加 | |
MidiEvent note_off_event = MidiEvent::makeNoteOffEvent(note.channel, note.note_number, 0, note.end_tick); | |
tracks[note.track].push_back(note_off_event); | |
} | |
// トラックを追加 | |
for (int i = 0; i < num_tracks_; i++) { | |
if (!tracks[i].empty()) { | |
midi_file.addTrack(tracks[i]); | |
} | |
} | |
// MIDIファイルを書き出し | |
midi_file.write(path); | |
} | |
private: | |
// MIDIノート | |
struct MidiNote { | |
int track; // トラック番号 | |
int channel; // MIDIチャンネル | |
int note_number; // MIDIノートナンバー | |
int velocity; // MIDIベロシティ | |
int start_tick; // 開始ティック | |
int end_tick; // 終了ティック | |
ImColor color; // 色 | |
}; | |
/ 時間情報 | |
struct TimeInfo { | |
int tick; // ティック | |
int measure; // 小節数 | |
int beat; // 拍数 | |
int tick_in_beat; // 拍内のティック数 | |
int tick_in_measure;// 小節内のティック数 | |
}; | |
// 拍子記号 | |
struct TimeSignature { | |
int numerator; // 分子 | |
int denominator; // 分母 | |
}; | |
// キーボード | |
struct Keyboard { | |
static const int NUM_WHITE_KEYS = 7; | |
static const int NUM_BLACK_KEYS = 5; | |
static const int NUM_KEYS = NUM_WHITE_KEYS + NUM_BLACK_KEYS; | |
int key_offset = 0; // キーのオフセット | |
int note_number[NUM_KEYS] = { 0 }; // キーのMIDIノートナンバー | |
// キーの描画 | |
void draw(ImDrawList* draw_list, ImVec2 pos, ImVec2 size, ImColor color_white_key, ImColor color_black_key) { | |
ImVec2 white_key_size(size.x / NUM_WHITE_KEYS, size.y); | |
ImVec2 black_key_size(white_key_size.x * 0.6f, white_key_size.y * 0.6f); | |
ImVec2 key_pos = pos; | |
for (int i = 0; i < NUM_WHITE_KEYS; i++) { | |
if (note_number[i] != -1) { | |
draw_list->AddRectFilled(key_pos, key_pos + white_key_size, color_white_key); | |
draw_list->AddRect(key_pos, key_pos + white_key_size, ImColor(0, 0, 0), 0.0f, ImDrawCornerFlags_All, 2.0f); | |
} | |
key_pos.x += white_key_size.x; | |
} | |
key_pos = pos + ImVec2(white_key_size.x * 0.6f, 0.0f); | |
for (int i = 0; i < NUM_BLACK_KEYS; i++) { | |
if (note_number[NUM_WHITE_KEYS + i] != -1) { | |
draw_list->AddRectFilled(key_pos, key_pos + black_key_size, color_black_key); | |
draw_list->AddRect(key_pos, key_pos + black_key_size, ImColor(0, 0, 0), 0.0f, ImDrawCornerFlags_All, 2.0f); | |
} | |
key_pos.x += white_key_size.x; | |
if (i == 1) { | |
key_pos.x += white_key_size.x; | |
} | |
} | |
} | |
// キーのMIDIノートナンバーを設定 | |
void set_note_number(int note_offset) { | |
key_offset = note_offset; | |
note_number[0] = note_offset + 0; | |
note_number[1] = note_offset + 2; | |
note_number[2] = note_offset + 4; | |
note_number[3] = note_offset + 5; | |
note_number[4] = note_offset + 7; | |
note_number[5] = note_offset + 9; | |
note_number[6] = note_offset + 11; | |
note_number[7] = -1; | |
note_number[8] = note_offset + 1; | |
note_number[9] = note_offset + 3; | |
note_number[10] = -1; | |
note_number[11] = note_offset + 6; | |
note_number[12] = note_offset + 8; | |
note_number[13] = note_offset + 10; | |
note_number[14] = -1; | |
} | |
}; | |
// ピアノロールの設定 | |
struct PianoRollSettings { | |
bool show_time_signature = true; // 拍子記号を表示するかどうか | |
bool show_grid = true; // グリッドを表示するかどうか | |
int grid_division = 16; // グリッドの分割数 | |
int snap = 4; // スナップ値 | |
int piano_key_offset = 36; // ピアノロール上のキーのオフセット | |
int piano_key_width = 12; // ピアノロール上のキーの幅 | |
int min_note_length = 2; // 最小の音符の長さ | |
int max_note_length = 16; // 最大の音符の長さ | |
ImColor grid_color = ImColor(255, 255, 255, 32); // グリッドの色 | |
ImColor time_signature_color = ImColor(255, 255, 255, 128); // 拍子記号の色 | |
ImColor active_note_color = ImColor(255, 255, 255, 128); // アクティブなノートの色 | |
ImColor note_color = ImColor(255, 255, 255, 64); // ノートの色 | |
ImColor black_key_color = ImColor(0, 0, 0); // 黒鍵の色 | |
ImColor white_key_color = ImColor(255, 255, 255); // 白鍵の色 | |
}; | |
// ノートの状態 | |
enum class NoteState { | |
NONE, // 選択されていない | |
SELECTED, // 選択された | |
DRAGGING, // ドラッグ中 | |
RESIZING, // リサイズ中 | |
}; | |
// ノートの矩形情報 | |
struct NoteRect { | |
int track; // トラック番号 | |
int channel; // MIDIチャンネル | |
int note_number; // MIDIノートナンバー | |
int start_tick; // 開始ティック | |
int end_tick; // 終了ティック | |
int length; // 長さ | |
NoteState state; // 状態 | |
ImVec2 pos; // 左上の座標 | |
ImVec2 size; // サイズ | |
}; | |
// MIDIファイルのロード | |
void LoadMidiFile(const char* path) { | |
// MIDIファイルを読み込む | |
std::unique_ptr<MidiFile> midi_file(new MidiFile()); | |
midi_file->read(path); | |
// MIDIファイルからトラックを生成する | |
for (int i = 0; i < midi_file->getTrackCount(); i++) { | |
tracks.emplace_back(); | |
auto& track = tracks.back(); | |
auto& midi_track = midi_file->getTrack(i); | |
int current_tick = 0; | |
for (auto& event : midi_track) { | |
current_tick += event.tick; | |
if (event.isNoteOn()) { | |
// ノートオンイベントの場合は新しいノートを生成する | |
track.emplace_back(); | |
auto& note = track.back(); | |
note.track = tracks.size() - 1; | |
note.channel = event.getChannel(); | |
note.note_number = event.getKeyNumber(); | |
note.start_tick = current_tick; | |
note.end_tick = current_tick; | |
note.length = 0; | |
note.state = NoteState::NONE; | |
} | |
else if (event.isNoteOff()) { | |
// ノートオフイベントの場合は対応するノートの終了時刻を更新する | |
for (auto& note : track) { | |
if (note.channel == event.getChannel() && note.note_number == event.getKeyNumber() && note.end_tick == current_tick) { | |
note.end_tick = current_tick; | |
note.length = std::max(note.end_tick - note.start_tick, piano_roll_settings.min_note_length); | |
break; | |
} | |
} | |
} | |
} | |
} | |
// グリッドの数を計算する | |
int max_tick = 0; | |
for (auto& track : tracks) { | |
for (auto& note : track) { | |
max_tick = std::max(max_tick, note.end_tick); | |
} | |
} | |
grid_count = (max_tick + piano_roll_settings.grid_division - 1) / piano_roll_settings.grid_division; | |
} | |
// MIDIファイルの保存 | |
void SaveMidiFile(const char* path) { | |
// MIDIファイルを生成する | |
std::unique_ptr<MidiFile> midi_file(new MidiFile()); | |
midi_file->setTicksPerQuarter(piano_roll_settings.grid_division); | |
// MIDIトラックを生成する | |
std::vector<std::unique_ptr<MidiTrack>> midi_tracks; | |
for (auto& track : tracks) { | |
midi_tracks.emplace_back(new MidiTrack()); | |
auto& midi_track = *midi_tracks.back(); | |
int current_tick = 0; | |
for (auto& note : track) { | |
if (note.length > 0) { | |
// ノートオンイベントを生成する | |
midi_track.addNoteOn(note.channel, current_tick, note.note_number, 127); | |
// ノートオフイベントを生成する | |
midi_track.addNoteOff(note.channel, current_tick + note.length, note.note_number, 0); | |
} | |
current_tick = note.end_tick; | |
} | |
// トラックの末尾にエンドイベントを追加する | |
midi_track.addEndOfTrack(current_tick); | |
} | |
// MIDIトラックをMIDIファイルに設定する | |
for (auto& midi_track : midi_tracks) { | |
midi_file->addTrack(*midi_track); | |
} | |
// MIDIファイルを保存する | |
midi_file->write(path); | |
} | |
// ノートを描画する | |
void DrawNote(const PianoRollNote& note, ImDrawList* draw_list, const ImVec2& offset, float key_height, float grid_width) { | |
// ノートの位置とサイズを計算する | |
float x = offset.x + note.start_tick / (float)piano_roll_settings.grid_division * grid_width; | |
float y = offset.y + (127 - note.note_number) * key_height; | |
float width = note.length / (float)piano_roll_settings.grid_division * grid_width; | |
float height = key_height; | |
// ノートの色を決定する | |
ImU32 color = ImColor(piano_roll_settings.note_colors[note.track % piano_roll_settings.note_colors.size()]); | |
// ノートを描画する | |
draw_list->AddRectFilled(ImVec2(x, y), ImVec2(x + width, y + height), color); | |
} | |
// ピアノロールを描画する | |
void DrawPianoRoll() { | |
// ピアノロールの領域を計算する | |
ImVec2 pos = ImGui::GetCursorScreenPos(); | |
ImVec2 size = ImGui::GetContentRegionAvail(); | |
size.x = std::max(size.x, 100.0f); | |
size.y = std::max(size.y, 100.0f); | |
ImVec2 end_pos = pos + size; | |
// ピアノロールのグリッド幅とキーの高さを計算する | |
float grid_width = size.x / grid_count; | |
float key_height = size.y / 128; | |
// ピアノロールの枠を描画する | |
ImGui::GetWindowDrawList()->AddRect(pos, end_pos, ImGui::GetColorU32(ImGuiCol_Border), 0.0f, ImDrawCornerFlags_All, 1.0f); | |
// キーを描画する | |
for (int i = 0; i < 128; i++) { | |
// キーの範囲を計算する | |
float key_top = pos.y + (127 - i) * key_height; | |
float key_bottom = key_top + key_height; | |
// キーを描画する | |
ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(pos.x, key_top), ImVec2(end_pos.x, key_bottom), piano_roll_settings.key_colors[i % piano_roll_settings.key_colors.size()]); | |
ImGui::GetWindowDrawList()->AddLine(ImVec2(pos.x, key_top), ImVec2(end_pos.x, key_top), 0xFFFFFFFF); | |
} | |
// グリッドを描画する | |
for (int i = 0; i <= grid_count; i++) { | |
float x = pos.x + i * grid_width; | |
ImGui::GetWindowDrawList()->AddLine(ImVec2(x, pos.y), ImVec2(x, end_pos.y), 0xFFFFFFFF); | |
} | |
// ノートを描画する | |
for (auto& track : tracks) { | |
for (auto& note : track) { | |
DrawNote(note, ImGui::GetWindowDrawList(), pos, key_height, grid_width); | |
} | |
} | |
// ピアノロールのスクロールを可能にする | |
if (ImGui::IsWindowHovered() && ImGui::IsMouseDragging(ImGuiMouseButton_Left)) { | |
scroll_offset.x -= ImGui::GetIO().MouseDelta.x; | |
scroll_offset.y -= ImGui::GetIO().MouseDelta.y; | |
} | |
} | |
// MIDIファイルを読み込む | |
void LoadMidiFile(const std::string& path) { | |
// MIDIファイルを読み込む | |
std::unique_ptr<midi::MidiFile> midi_file = std::make_unique<midi::MidiFile>(); | |
midi_file->read(path); | |
// トラックを初期化する | |
tracks.clear(); | |
for (int i = 0; i < midi_file->getTrackCount(); i++) { | |
tracks.emplace_back(); | |
} | |
// MIDIイベントを処理する | |
for (int i = 0; i < midi_file->getEventCount(); i++) { | |
auto event = midi_file->getEvent(i); | |
int track = event->track; | |
if (event->isNoteOn()) { | |
int note_number = event->getNoteNumber(); | |
int velocity = event->getVelocity(); | |
int tick = event->tick; | |
int length = 0; | |
for (int j = i + 1; j < midi_file->getEventCount(); j++) { | |
auto next_event = midi_file->getEvent(j); | |
if (next_event->isNoteOff() && next_event->track == track && next_event->getNoteNumber() == note_number) { | |
length = next_event->tick - tick; | |
break; | |
} | |
} | |
tracks[track].push_back({ note_number, velocity, tick, length }); | |
} | |
} | |
} | |
}; | |
int main(int argc, char** argv) { | |
// ImGuiを初期化する | |
ImGui::CreateContext(); | |
ImGuiIO& io = ImGui::GetIO(); | |
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; | |
// GLFWを初期化する | |
glfwInit(); | |
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); | |
GLFWwindow* window = glfwCreateWindow(1280, 720, "ImGui Piano Roll", nullptr, nullptr); | |
// ImGui GLFW3 バインディングを初期化する | |
ImGui_ImplGlfw_InitForVulkan(window, true); | |
// ImGui Vulkan バインディングを初期化する | |
VkInstance instance = CreateVulkanInstance(); | |
VkPhysicalDevice physical_device = PickPhysicalDevice(instance); | |
VkDevice device = CreateDevice(physical_device); | |
VkSurfaceKHR surface = CreateSurface(instance, window); | |
VkQueue graphics_queue = GetGraphicsQueue(device); | |
VkCommandPool command_pool = CreateCommandPool(device, graphics_queue); | |
VkRenderPass render_pass = CreateRenderPass(device); | |
VkPipelineLayout pipeline_layout = CreatePipelineLayout(device); | |
VkPipeline pipeline = CreatePipeline(device, pipeline_layout, render_pass); | |
std::vector<VkFramebuffer> framebuffers = CreateFramebuffers(device, render_pass, surface); | |
VkCommandBuffer command_buffer = BeginSingleTimeCommands(device, command_pool); | |
// ピアノロールを初期化する | |
PianoRoll piano_roll; | |
// メインループ | |
while (!glfwWindowShouldClose(window)) { | |
// イベントを処理する | |
glfwPollEvents(); | |
// ImGui GLFW3 バインディングを更新する | |
ImGui_ImplGlfw_NewFrame(); | |
// ImGui フレームを開始する | |
ImGui::NewFrame(); | |
// メニューバーを表示する | |
if (ImGui::BeginMainMenuBar()) { | |
if (ImGui::BeginMenu("File")) { | |
if (ImGui::MenuItem("Open MIDI File")) { | |
// MIDIファイルを開くダイアログを表示する | |
nfdchar_t* path = nullptr; | |
nfdresult_t result = NFD_OpenDialog("mid", nullptr, &path); | |
if (result == NFD_OKAY) { | |
// MIDIファイルを読み込む | |
piano_roll.LoadMidiFile(path); | |
free(path); | |
} | |
} | |
ImGui::EndMenu(); | |
} | |
ImGui::EndMainMenuBar(); | |
} | |
// ピアノロールを更新する | |
piano_roll.Update(); | |
// ImGui フレームを描画する | |
ImGui::Render(); | |
// レンダリングを開始する | |
VkSemaphore image_available_semaphore = CreateSemaphore(device); | |
VkSemaphore render_finished_semaphore = CreateSemaphore(device); | |
uint32_t image_index = 0; | |
VkResult result = vkAcquireNextImageKHR(device, GetSwapchain(device), UINT64_MAX, image_available_semaphore, VK_NULL_HANDLE, &image_index); | |
if (result == VK_ERROR_OUT_OF_DATE_KHR) { | |
RecreateSwapchain(device, physical_device, surface, render_pass, pipeline_layout, pipeline, framebuffers); | |
} | |
else if (result != VK_SUCCESS && result != VK_SUBOPTIMAL_KHR) { | |
throw std::runtime_error("Failed to acquire swapchain image."); | |
} | |
// コマンドバッファをリセットする | |
vkResetCommandBuffer(command_buffer, 0); | |
// レンダーパスを開始する | |
VkClearValue clear_value = { 0.0f, 0.0f, 0.0f, 1.0f }; | |
VkRenderPassBeginInfo render_pass_begin_info = { | |
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, | |
nullptr, | |
render_pass, | |
framebuffers[image_index], | |
{ | |
{ 0, 0 }, | |
GetSwapchainExtent(device) | |
}, | |
1, | |
&clear_value | |
}; | |
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE); | |
// ピアノロールを描画する | |
piano_roll.Draw(command_buffer, pipeline_layout, pipeline); | |
// レンダーパスを終了する | |
vkCmdEndRenderPass(command_buffer); | |
// レンダリングを終了する | |
EndSingleTimeCommands(device, command_pool, graphics_queue, command_buffer); | |
PresentImage(device, GetSwapchain(device), graphics_queue, image_index, render_finished_semaphore); | |
// ImGui Vulkan バインディングを更新する | |
ImGui_ImplVulkan_NewFrame(); | |
// ImGui Vulkan バインディングで描画する | |
VkCommandBuffer ImGui_command_buffer = ImGui_ImplVulkan_RenderDrawData(ImGui::GetDrawData(), command_buffer); | |
EndSingleTimeCommands(device, command_pool, graphics_queue, ImGui_command_buffer); | |
// スワップチェインにイメージをプレゼントする | |
PresentImage(device, GetSwapchain(device), graphics_queue, image_index, render_finished_semaphore); | |
// フレームを終了する | |
vkQueueWaitIdle(graphics_queue); | |
vkFreeSemaphore(device, image_available_semaphore, nullptr); | |
vkFreeSemaphore(device, render_finished_semaphore, | |
} | |
// ImGui Vulkan バインディングを解放する | |
ImGui_ImplVulkan_Shutdown(); | |
// ImGui バインディングを解放する | |
ImGui::DestroyContext(); | |
// ピアノロールを解放する | |
piano_roll.Unload(); | |
// フレームバッファを解放する | |
for (VkFramebuffer framebuffer : framebuffers) { | |
vkDestroyFramebuffer(device, framebuffer, nullptr); | |
} | |
// パイプラインを解放する | |
vkDestroyPipeline(device, pipeline, nullptr); | |
vkDestroyPipelineLayout(device, pipeline_layout, nullptr); | |
vkDestroyRenderPass(device, render_pass, nullptr); | |
// デプスステンシルバッファを解放する | |
vkDestroyImageView(device, depth_stencil_view, nullptr); | |
vkDestroyImage(device, depth_stencil_image, nullptr); | |
vkFreeMemory(device, depth_stencil_memory, nullptr); | |
// スワップチェインを解放する | |
vkDestroySwapchainKHR(device, swapchain, nullptr); | |
// インデックスバッファを解放する | |
vkDestroyBuffer(device, index_buffer, nullptr); | |
vkFreeMemory(device, index_buffer_memory, nullptr); | |
// 頂点バッファを解放する | |
vkDestroyBuffer(device, vertex_buffer, nullptr); | |
vkFreeMemory(device, vertex_buffer_memory, nullptr); | |
// コマンドプールを解放する | |
vkDestroyCommandPool(device, command_pool, nullptr); | |
// グラフィックスパイプライン用のセマフォを解放する | |
vkDestroySemaphore(device, graphics_semaphore, nullptr); | |
vkDestroySemaphore(device, present_semaphore, nullptr); | |
// デバイスを解放する | |
vkDestroyDevice(device, nullptr); | |
// インスタンスを解放する | |
vkDestroyInstance(instance, nullptr); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment