MIDI 文件中的未知日文编码

Unknown Japanese encoding in MIDI file

我有一个我认为包含日语字符的 MIDI 文件(从 https://www.mediafire.com/file/y8wp3bd7at1agnd/Africa.rar/file 下载)。不幸的是,none 我试过的 MIDI 程序似乎能够正确解码日语。

例如,一些乐器名称显示为

ƒp[ƒJƒbƒVƒ‡ƒ“‚Piƒ}ƒbƒv‚Pj•ƒeƒ“ƒ|�

# hex bytes (from od -t x1)
0000000    c2  83  70  c2  81  5b  c2  83  4a  c2  83  62  c2  83  56  c2
0000020    83  c2  87  c2  83  c2  93  c2  82  50  c2  81  69  c2  83  7d
0000040    c2  83  62  c2  83  76  c2  82  50  c2  81  6a  c2  81  c2  95
0000060    c2  83  65  c2  83  c2  93  c2  83  7c  ef  bf  bd

ƒMƒ^[•‰ŠúÝ’è•‚eD‚n�

# hex bytes (from od -t x1)
0000000    c2  83  4d  c2  83  5e  c2  81  5b  c2  81  c2  95  c2  8f  c2
0000020    89  c2  8a  c3  ba  c2  90  c3  9d  c2  92  c3  a8  c2  81  c2
0000040    95  c2  82  65  c2  81  44  c2  82  6e  ef  bf  bd

我使用脚本对 iconv 知道的每个转换进行暴力尝试(感谢 https://unix.stackexchange.com/a/184565),我得到了一些 几乎 使用 SHIFT_JISX0213 编码可读。

ツパツーツカツッツシツδ傔δ督1ツ(ツマツッツプツ1ツ)ツ⊊閉テツδ督ポ魹ス
ツギツタツーツ⊊閉渉可甘コツ静敖津ィツ⊊閉Fツ.ツO魹ス

可见有几个片假名单词穿插ツ字:“Percussion”(パーカッシ)、“Map 1”(マップ1)、“Guitar”(ギター)。我不知道如何理解该行的其余部分(我看不懂日文所以我依赖 Google 翻译)。

有人知道正确的编码应该是什么吗?

事实证明,上面的字节串并不存在于原始 MIDI 文件中。它们被我使用的 MIDI reader 破坏了。

借助于 http://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html 我能够编写一个简单的 C 程序来提取原始字节,这些字节采用基本的 SHIFT-JIS 编码。

% cc extract_instruments.c -o extract_instruments
% cat AFRICA_55.MID| ./extract_instruments| iconv -f SHIFT-JIS -t UTF8
【  AFRICA / TOTO  】   for SC-55      by  染之介
...

extract_instruments.c:

#include <stdio.h>

/*
   Acknowledgement:
   ReadVarLen is derived from http://www.music.mcgill.ca/~ich/classes/mumt306/StandardMIDIfileformat.html#BMA2_
   (c) Copyright 1999 David Back.
   EMail: david@csw2.co.uk
   Web: http://www.csw2.co.uk
   This document may be freely copied in whole or in part provided the copy contains
   this Acknowledgement. 
*/
int ReadVarLen() {
   register int value;
   register char c;
   
   if((value = getchar()) & 0x80) {
      value &= 0x7f;
      do {
     value = (value << 7) + ((c = getchar()) & 0x7f);
      } while (c & 0x80);
   }
   
   return(value);
}

void ReadAndPrintName(int length) {
   char name[length+1];
   fgets(name, length+1, stdin);
   printf("%s\n", name);
}

int main() {
   int c1 = 0;
   int c2 = getchar();

   while (c2 != EOF) {
     
     // 0xFF03 == Sequence/Track Name
     if (c1 == 0xff && c2 == 0x03) {
       int length = ReadVarLen();
       ReadAndPrintName(length);
     }
     
     c1 = c2;
     c2 = getchar();
   }

   return 0;
}