首页 > 解决方案 > MIDI 文件中未知的日语编码

问题描述

我有一个我认为包含日语字符的 MIDI 文件(从https://www.mediafire.com/file/y8wp3bd7at1agnd/Africa.rar/file下载)。不幸的是,我尝试过的所有 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魹ス

有几个可见的片假名单词穿插着ツ字符:“打击乐器”(パーカッシ)、“地图1”(マップ1)、“吉他”(ギター)。我不知道如何理解这行的其余部分(我看不懂日语,所以我依赖谷歌翻译)。

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

标签: character-encodingmidicjk

解决方案


事实证明,上面的字节字符串不存在于原始 MIDI 文件中。它们被我使用的 MIDI 阅读器弄坏了。

在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;
}

推荐阅读