-- プラグイン情報
function getClientInfo()
  return {
    name = "歌唱化用 SRT と MIDI のエクスポート",
    category = "エクスポート",
    author = "水っぽいスープ",
    versionNumber = 6,
    minEditorVersion = 65540
  }
end

function to_varlen(val)
  local buffer = {}
  repeat
    local b = val % 128
    val = math.floor(val / 128)
    if #buffer > 0 then b = b + 128 end
    table.insert(buffer, 1, b)
  until val == 0
  return string.char(table.unpack(buffer))
end

function to_bytes(val, length)
  local str = ""
  for i = length - 1, 0, -1 do
    local b = math.floor(val / (256 ^ i)) % 256
    str = str .. string.char(b)
  end
  return str
end

function time_format(time)
  local hour = math.floor(time % 86400 / 3600)
  local min = math.floor(time % 3600 / 60)
  local sec = math.floor(time % 60)
  local mili = math.floor((time - math.floor(time))*1000 + 0.5)
  return string.format("%02d:%02d:%02d,%03d", hour, min, sec, mili)
end

-- メイン関数
function main()


-- グループの数を数える
 local NumGroups = SV:getMainEditor():getCurrentTrack():getNumGroups()

 if NumGroups < 3 then



  local Filepath = SV:getProject():getFileName()

  if Filepath ~= "" then
    -- 1. 歌詞のローマ字安全チェック
    local Notes = SV:getMainEditor():getCurrentGroup():getTarget()
    local NumNotes = Notes:getNumNotes()
    local has_romaji = false
    local error_lyric = ""

    for i = 1, NumNotes do
      local lyric = Notes:getNote(i):getLyrics()
      if string.find(lyric, "[A-Za-z]") then
        has_romaji = true
        error_lyric = lyric
        break
      end
    end

    if has_romaji then
      SV:showMessageBox("書き出し中断", "エラー: ローマ字の歌詞（「" .. error_lyric .. "」）が含まれています。\nひらがな・カタカナに修正してください。")
      SV:finish()
      return
    end

    -- 2. 保存ファイル名指定ダイアログ
    local myForm = {
      title = "歌唱化用データの出力",
      message = "歌唱化用SRTと、VocalShifter用のMIDIを同時に保存します。\n半角英数字のみのディレクトリ・ファイル名にしてください。",
      buttons = "OkCancel",
      widgets = {
        {
          name = "tb1", type = "TextBox",
          label = "保存する名前",
          default = "singing_data"
        }
      }
    }

    local result = SV:showCustomDialog(myForm)
    local filedir = string.match(Filepath, ".+\\")
    
    local srt_filename = filedir .. tostring(result.answers.tb1) .. ".srt"
    local mid_filename = filedir .. tostring(result.answers.tb1) .. ".mid"

    if result.status then
      -- ----------------------------------------------------
      -- A面: VOICEPEAK用の SRT ファイル書き出し
      -- ----------------------------------------------------
      local srttext = ""
      for i = 1, NumNotes do
        local start = Notes:getNote(i):getOnset()
        local stop = Notes:getNote(i):getEnd()
        local lyric = Notes:getNote(i):getLyrics()
        local start_sec = SV:getProject():getTimeAxis():getSecondsFromBlick(start)
        local stop_sec = SV:getProject():getTimeAxis():getSecondsFromBlick(stop)
        local check_sec = stop_sec - start_sec

      local boin = ""

      if string.find(lyric, "ぁ") or string.find(lyric, "ァ") or string.find(lyric, "ゃ") or string.find(lyric, "ャ") or string.find(lyric, "a") then
         boin = "あ"
      elseif string.find(lyric, "ぃ") or string.find(lyric, "ィ") or string.find(lyric, "i") then
         boin = "い"
      elseif string.find(lyric, "ぅ") or string.find(lyric, "ゥ") or string.find(lyric, "ゅ") or string.find(lyric, "ュ") or string.find(lyric, "u") then
         boin = "う"
      elseif string.find(lyric, "ぇ") or string.find(lyric, "ェ") or string.find(lyric, "e") then
         boin = "え"
      elseif string.find(lyric, "ぉ") or string.find(lyric, "ォ") or string.find(lyric, "ょ") or string.find(lyric, "ョ") or string.find(lyric, "o") then
         boin = "お"

-- 母音
      elseif string.find(lyric, "あ") or string.find(lyric, "か") or string.find(lyric, "が") or string.find(lyric, "さ") or string.find(lyric, "ざ")  or string.find(lyric, "た") or string.find(lyric, "だ") or string.find(lyric, "な") or string.find(lyric, "は") or string.find(lyric, "ば") or string.find(lyric, "ぱ") or string.find(lyric, "ま") or string.find(lyric, "や") or string.find(lyric, "ら") or string.find(lyric, "わ") or string.find(lyric, "ア") or string.find(lyric, "カ") or string.find(lyric, "ガ") or string.find(lyric, "サ") or string.find(lyric, "ザ")  or string.find(lyric, "タ") or string.find(lyric, "ダ") or string.find(lyric, "ナ") or string.find(lyric, "ハ") or string.find(lyric, "バ") or string.find(lyric, "パ") or string.find(lyric, "マ") or string.find(lyric, "ヤ") or string.find(lyric, "ラ") or string.find(lyric, "ワ")  then
         boin = "あ"

      elseif string.find(lyric, "い") or string.find(lyric, "き") or string.find(lyric, "ぎ") or string.find(lyric, "し") or string.find(lyric, "じ")  or string.find(lyric, "ち") or string.find(lyric, "ぢ") or string.find(lyric, "に") or string.find(lyric, "ひ") or string.find(lyric, "び") or string.find(lyric, "ぴ") or string.find(lyric, "み") or string.find(lyric, "り") or string.find(lyric, "イ") or string.find(lyric, "キ") or string.find(lyric, "ギ") or string.find(lyric, "シ") or string.find(lyric, "ジ")  or string.find(lyric, "チ") or string.find(lyric, "ヂ") or string.find(lyric, "ニ") or string.find(lyric, "ヒ") or string.find(lyric, "ビ") or string.find(lyric, "ピ") or string.find(lyric, "ミ") or string.find(lyric, "リ") then
         boin = "い"

      elseif string.find(lyric, "う") or string.find(lyric, "く") or string.find(lyric, "ぐ") or string.find(lyric, "す") or string.find(lyric, "ず")  or string.find(lyric, "つ") or string.find(lyric, "づ") or string.find(lyric, "ぬ") or string.find(lyric, "ふ") or string.find(lyric, "ぶ") or string.find(lyric, "ぷ") or string.find(lyric, "む") or string.find(lyric, "ゆ") or string.find(lyric, "る") or string.find(lyric, "ウ") or string.find(lyric, "ク") or string.find(lyric, "グ") or string.find(lyric, "ス") or string.find(lyric, "ズ")  or string.find(lyric, "ツ") or string.find(lyric, "ヅ") or string.find(lyric, "ヌ") or string.find(lyric, "フ") or string.find(lyric, "ブ") or string.find(lyric, "プ") or string.find(lyric, "ム") or string.find(lyric, "ユ") or string.find(lyric, "ル") then
         boin = "う"

      elseif string.find(lyric, "え") or string.find(lyric, "け") or string.find(lyric, "げ") or string.find(lyric, "せ") or string.find(lyric, "ぜ")  or string.find(lyric, "て") or string.find(lyric, "で") or string.find(lyric, "ね") or string.find(lyric, "へ") or string.find(lyric, "べ") or string.find(lyric, "ぺ") or string.find(lyric, "め") or string.find(lyric, "れ") or string.find(lyric, "エ") or string.find(lyric, "ケ") or string.find(lyric, "ゲ") or string.find(lyric, "セ") or string.find(lyric, "ゼ")  or string.find(lyric, "テ") or string.find(lyric, "デ") or string.find(lyric, "ネ") or string.find(lyric, "ヘ") or string.find(lyric, "ベ") or string.find(lyric, "ペ") or string.find(lyric, "メ") or string.find(lyric, "レ") then
         boin = "え"

      elseif string.find(lyric, "お") or string.find(lyric, "こ") or string.find(lyric, "ご") or string.find(lyric, "そ") or string.find(lyric, "ぞ")  or string.find(lyric, "と") or string.find(lyric, "ど") or string.find(lyric, "の") or string.find(lyric, "ほ") or string.find(lyric, "ぼ") or string.find(lyric, "ぽ") or string.find(lyric, "も") or string.find(lyric, "よ") or string.find(lyric, "ろ") or string.find(lyric, "オ") or string.find(lyric, "コ") or string.find(lyric, "ゴ") or string.find(lyric, "ソ") or string.find(lyric, "ゾ")  or string.find(lyric, "ト") or string.find(lyric, "ド") or string.find(lyric, "ノ") or string.find(lyric, "ホ") or string.find(lyric, "ボ") or string.find(lyric, "ポ") or string.find(lyric, "モ") or string.find(lyric, "ヨ") or string.find(lyric, "ロ") then
         boin = "お"

-- ん
      elseif  string.find(lyric, "ん") or string.find(lyric,"ン") or string.find(lyric, "n") then
         boin = "ん"

-- 変換できない
      else
         boin = "ー"
      end

        local bartext =""
        for j=1, check_sec/0.5 do
        bartext = bartext .. boin
        end
        srttext = srttext .. i .. "\n" .. time_format(start_sec) .. " --> " .. time_format(stop_sec) .. "\n" .. lyric ..bartext .. "\n\n"
      end
      local f_srt = io.open(srt_filename, "w")
      if f_srt then f_srt:write(srttext) f_srt:close() end

      -- ----------------------------------------------------
      -- B面: MIDI（楽譜バイナリ）の書き出し
      -- ----------------------------------------------------
      local track_data = ""
      local NumGroups = SV:getMainEditor():getCurrentTrack():getNumGroups()
      local all_notes = {}

      for j = 1, NumGroups do
        local targetGroup = SV:getMainEditor():getCurrentTrack():getGroupReference(j):getTarget()
        local n_count = targetGroup:getNumNotes()
        for i = 1, n_count do
          local note = targetGroup:getNote(i)
          local start_tick = math.floor(note:getOnset() * 480 / 705600000)
          local end_tick = math.floor((note:getOnset() + note:getDuration()) * 480 / 705600000)
          table.insert(all_notes, {onset = start_tick, offset = end_tick, pitch = note:getPitch()})
        end
      end

      table.sort(all_notes, function(a, b) return a.onset < b.onset end)

      local last_tick = 0
      for _, n in ipairs(all_notes) do
        local delta_on = n.onset - last_tick
        track_data = track_data .. to_varlen(delta_on) .. string.char(0x90, n.pitch, 100)
        local delta_off = n.offset - n.onset
        track_data = track_data .. to_varlen(delta_off) .. string.char(0x80, n.pitch, 0)
        last_tick = n.offset
      end
      track_data = track_data .. to_varlen(0) .. string.char(0xFF, 0x2F, 0x00)

      local header = "MThd" .. to_bytes(6, 4) .. to_bytes(0, 2) .. to_bytes(1, 2) .. to_bytes(480, 2)
      local track = "MTrk" .. to_bytes(#track_data, 4) .. track_data

      local f_mid = io.open(mid_filename, "wb")
      if f_mid then f_mid:write(header .. track) f_mid:close() end

      SV:showMessageBox("エクスポート完了", "同じフォルダに以下を出力しました。\n・" .. tostring(result.answers.tb1) .. ".srt (歌唱化用)\n・" .. tostring(result.answers.tb1) .. ".mid (VocalShifter用)")
    end
  else
    SV:showMessageBox("注意", "SynthVのファイルを先に保存してください。")
  end

   else
   SV:showMessageBox("注意" ,"複数グループに対応していません。\n1トラック1グループでお願いします。")
  end

  SV:finish()
end
