2014-05-06

Medoly ver.1.3.1 & 1.3.2 & 1.3.3

Medoly


ちょっと変更。

Ver. 1.3.1

 

検索画面の検索条件やスクロール位置をなるべく保持させる処理を追加

アプリの再起動時や検索画面に戻った時、検索条件を切り替えた時に、検索条件やスクロール位置を可能な限り保持するようにしました。
「可能な限り」というのは、曲が追加されたり変更された際に、どうしても位置を保持することが難しくなるため、そういった場合はズレが生じてきます。
保持させるタイミングや復帰させるタイミングがかなり入り組んでいて、色々面倒臭い処理になっているため、もしかしたらリセットされる場合があるかもしれません…。

再生キューのトラック・年が隠れないようにレイアウトを変更

再生キューには、アルバム名にディスク/トラック番号、アーティスト名に年が併記されていますが、アルバム名・アーティスト名が長い場合は ディスク/トラック番号・年が枠外に隠れてしまっていました。そんなわけで、 ディスク/トラック番号・年が隠れないようにレイアウトを修正しました。(アルバム名・アーティスト名のみが省略されます。)

Ver. 1.3.2

 

検索画面のアクティビティを再表示させた際、タイトル表示になってしまう問題を修正

Ver.1.3.1の修正ミスです。アクティビティ再表示が上手くいかないバグがありました。

Ver. 1.3.3

 

歌詞の多段表示対応

同じ時間で2行以上の歌詞がアクティブの場合、表示上も同時にアクティブにするようにしました。
2行以上が同時にアクティブになる場合は、行内にタイムタグが設定されている場合です。
例えば、以下のようなKRAファイルがあるとします。

[00:01:00] あ[00:02:00]い[00:03:00]う[00:04:00]え[00:05:00]お[00:06:00]
[00:04:00] か[00:05:00]き[00:06:00]く[00:07:00]け[00:08:00]こ[00:09:00]

上記の場合、再生開始から4~6秒の間は、1行目と2行目が両方アクティブな状態です。
文字単位で見ると、5秒時点では、1行目は「あ、い、う、え、お」が、2行目は「か、き」がアクティブな状態になります。
これは例えば、曲の中でメインボーカルとコーラスが被っている部分を表現する、といった利用を想定しています。

KRA -> LRC, LRC -> KRA 変換スクリプト

歌詞定義フォーマットの、LRCファイルKRAファイル(タイムタグフォーマット)の変換用WSHスクリプト(JScript)を作成したので公開。KRA -> LRC変換と、LRC -> KRA変換の2つ。WSHスクリプトなので、Windows専用。

[使い方]
  1. KRA -> LRC変換スクリプトの場合はKRAファイル(*.kra)をドラッグ&ドロップします。
    LRC -> KRA変換スクリプトの場合はLRCファイル(*.lrc)をドラッグ&ドロップします。
  2. KRAファイルの場合は、同じフォルダ上にLRCファイル(KRAファイル名.lrc)が作成されます。
    LRCファイルの場合は、同様にKRAファイルが作成されます。
[注意事項]
  • 埋め込まれているタグのうち、 タイトル、アーティスト、アルバム、作詞者、曲の長さ、ファイル作成者以外の情報は削除されます。
  • UnicodeのBOMが不要な場合は、コメントアウトしてある「// delete BOM」の辺りをコメント解除すると、BOMが削除されます。
  • あんまり真面目にテストしてないので、きちんと動かない場合があるかもしれません。 
  • とりあえず拡張子固定なので、拡張子lrcでKRAフォーマットにしている人や、拡張子txtでフォーマット定義してる人は知ったこっちゃないです。


KRA -> LRC変換WSHスクリプト


/*==== 設定 ==================================================================*/

var inputExt = /\.kra$/i;
var outputExt = ".lrc";
var inputEncoding = "_autodetect_all";
var outputEncoding = "UTF-8";

/*============================================================================*/



/*==== 定数 ==================================================================*/

// 保存データの種類
// StreamTypeEnum
// http://msdn.microsoft.com/ja-jp/library/cc389884.aspx
var adTypeBinary = 1; // バイナリ
var adTypeText   = 2; // テキスト

// 読み込み方法
// StreamReadEnum
// http://msdn.microsoft.com/ja-jp/library/cc389881.aspx
var adReadAll  = -1; // 全行
var adReadLine = -2; // 一行ごと

// 書き込み方法
// StreamWriteEnum
// http://msdn.microsoft.com/ja-jp/library/cc389886.aspx
var adWriteChar = 0; // 改行なし
var adWriteLine = 1; // 改行あり

// ファイルの保存方法
// SaveOptionsEnum 
// http://msdn.microsoft.com/ja-jp/library/cc389870.aspx
var adSaveCreateNotExist  = 1; // ない場合は新規作成
var adSaveCreateOverWrite = 2; // ある場合は上書き

/*============================================================================*/



var args = WScript.Arguments;
if (args.length == 0) {
 WScript.Echo("引数を指定するか、ファイルをドラッグ&ドロップしてください。");
 WScript.Quit();
}

for (var i = 0; i < args.length; i++) {
 var path = args(i);
 if (path.match(inputExt) != null) {
  writeLyrics(path);
 }
}

function writeLyrics(path) {
 var streamReader = new ActiveXObject("ADODB.Stream");
 var streamWriter = new ActiveXObject("ADODB.Stream");
 try {
  // read
  streamReader.Open();
  streamReader.Type = adTypeText;
  streamReader.Position = 0;
  streamReader.Charset = inputEncoding;
  streamReader.LoadFromFile( path );
  var text = streamReader.ReadText( adReadAll );
  if (text.charCodeAt(0) == 0xFEFF || text.charCodeAt(0) == 0xFFFE) {
   text = text.substr(1); // delete BOM
  }
  
  // replace
  text = text.replace(/(^\s+)|(\s+$)/g, "");
  text = text.replace(/(\r\n|\n|\r|^)\[(\d\d:\d\d)\:(\d\d)\]/g, "$1[$2.$3]");
  text = text.replace(/\[(\d\d:\d\d)\:(\d\d)\]/g, "<$1.$2>");
  
  text = text.replace(/@Title= *(.*?)(\r\n|\n|\r|$)/g, "[ti:$1]$2");
  text = text.replace(/@Artist= *(.*?)(\r\n|\n|\r|$)/g, "[ar:$1]$2");
  text = text.replace(/@Album= *(.*?)(\r\n|\n|\r|$)/g, "[al:$1]$2");
  text = text.replace(/@Lyricist= *(.*?)(\r\n|\n|\r|$)/g, "[au:$1]$2");
  text = text.replace(/@Length= *(.*?)(\r\n|\n|\r|$)/g, "[length:$1]$2");
  text = text.replace(/@TaggingBy= *(.*?)(\r\n|\n|\r|$)/g, "[by:$1]$2");
  
  var offset = text.match(/\@Offset= *(.*?)(\r\n|\n|\r|$)/);
  if (offset && offset.length >= 2) {
   text = text.replace(/\@Offset= *(.*?)(\r\n|\n|\r|$)/, "[offset:" + (offset[1] * -1) + "]$2");
  }
  
  text = text.replace(/(\@.*=.*?)(\r\n|\n|\r|$)/g, "");
  
  // write
  streamWriter.Type = adTypeText;
  streamWriter.Charset = outputEncoding;
  streamWriter.Open();
  streamWriter.WriteText(text, adWriteChar);
  
  /*
  // delete BOM
  var bomSize = 0;
  if (outputEncoding == "UTF-8") {
   bomSize = 3;
  } else if (outputEncoding.indexOf("UTF-16") == 0) {
   bomSize = 2;
  }
  streamWriter.Position = 0;
  streamWriter.Type = adTypeBinary;
  streamWriter.Position = bomSize;
  var buffer =  streamWriter.Read();
  streamWriter.Position = 0;
  streamWriter.Write(buffer);
  streamWriter.SetEOS();
  */
  
  streamWriter.SaveToFile( path.replace(inputExt, outputExt), adSaveCreateOverWrite );
 } finally {
  if (streamReader != null) streamReader.Close();
  if (streamWriter != null) streamWriter.Close();
 }
}

LRC -> KRA変換WSHスクリプト


/*==== 設定 ==================================================================*/

var inputExt = /\.lrc$/i;
var outputExt = ".kra";
var inputEncoding = "_autodetect_all";
var outputEncoding = "UTF-8";

/*============================================================================*/



/*==== 定数 ==================================================================*/

// 保存データの種類
// StreamTypeEnum
// http://msdn.microsoft.com/ja-jp/library/cc389884.aspx
var adTypeBinary = 1; // バイナリ
var adTypeText   = 2; // テキスト

// 読み込み方法
// StreamReadEnum
// http://msdn.microsoft.com/ja-jp/library/cc389881.aspx
var adReadAll  = -1; // 全行
var adReadLine = -2; // 一行ごと

// 書き込み方法
// StreamWriteEnum
// http://msdn.microsoft.com/ja-jp/library/cc389886.aspx
var adWriteChar = 0; // 改行なし
var adWriteLine = 1; // 改行あり

// ファイルの保存方法
// SaveOptionsEnum 
// http://msdn.microsoft.com/ja-jp/library/cc389870.aspx
var adSaveCreateNotExist  = 1; // ない場合は新規作成
var adSaveCreateOverWrite = 2; // ある場合は上書き

/*============================================================================*/



var args = WScript.Arguments;
if (args.length == 0) {
 WScript.Echo("引数を指定するか、ファイルをドラッグ&ドロップしてください。");
 WScript.Quit();
}

for (var i = 0; i < args.length; i++) {
 var path = args(i);
 if (path.match(inputExt) != null) {
  writeLyrics(path);
 }
}

function writeLyrics(path) {
 var streamReader = new ActiveXObject("ADODB.Stream");
 var streamWriter = new ActiveXObject("ADODB.Stream");
 try {
  // read
  streamReader.Open();
  streamReader.Type = adTypeText;
  streamReader.Position = 0;
  streamReader.Charset = inputEncoding;
  streamReader.LoadFromFile( path );
  var text = streamReader.ReadText( adReadAll );
  if (text.charCodeAt(0) == 0xFEFF || text.charCodeAt(0) == 0xFFFE) {
   text = text.substr(1); // delete BOM
  }
  
  // replace
  text = text.replace(/(^\s+)|(\s+$)/g, "");
  text = text.replace(/\<(\d\d:\d\d)\.(\d\d)\>/g, "[$1:$2]");
  text = text.replace(/\[(\d\d:\d\d)\.(\d\d)\]/g, "[$1:$2]");
  
  text = text.replace(/\[ti: *(.*?)\]/g, "@Title=$1");
  text = text.replace(/\[ar: *(.*?)\]/g, "@Artist=$1");
  text = text.replace(/\[al: *(.*?)\]/g, "@Album=$1");
  text = text.replace(/\[au: *(.*?)\]/g, "@Lyricist=$1");
  text = text.replace(/\[length: *(.*?)\]/g, "@Length=$1");
  text = text.replace(/\[by: *(.*?)\]/g, "@TaggingBy=$1");
  
  var offset = text.match(/\[offset: *(.*?)\]/);
  if (offset && offset.length >= 2) {
   text = text.replace(/\[offset: *(.*?)\]/, "@Offset=" + (offset[1] * -1));
  }
  
  text = text.replace(/\[[^\d].*?\](\r?\n)?/, "");
  text = text + "\r\n@TimeRatio=1\r\n";
  
  // write
  streamWriter.Type = adTypeText;
  streamWriter.Charset = outputEncoding;
  streamWriter.Open();
  streamWriter.WriteText(text, adWriteChar);
  
  /*
  // delete BOM
  var bomSize = 0;
  if (outputEncoding == "UTF-8") {
   bomSize = 3;
  } else if (outputEncoding.indexOf("UTF-16") == 0) {
   bomSize = 2;
  }
  streamWriter.Position = 0;
  streamWriter.Type = adTypeBinary;
  streamWriter.Position = bomSize;
  var buffer =  streamWriter.Read();
  streamWriter.Position = 0;
  streamWriter.Write(buffer);
  streamWriter.SetEOS();
  */
  
  streamWriter.SaveToFile( path.replace(inputExt, outputExt), adSaveCreateOverWrite );
 } finally {
  if (streamReader != null) streamReader.Close();
  if (streamWriter != null) streamWriter.Close();
 }
}

備考

タイムタグ仕様書(一般者向け)で定義されたフォーマットを「KRAフォーマット」と書いてはいますが、「KRAフォーマット」と言う名称はどこにも定義されてないので、便宜上の名前です。
「タイムタグ」や「タイムタグ歌詞」という名称は、LRC等を含めた歌詞定義フォーマット全般で使われる名称なので、フォーマット名称としてはあまり適切ではないと思います。そんなわけで、主に利用される拡張子「KRA」に基づき「KRAフォーマット」と呼称しています。
LRCは「LRCフォーマット」として定義されているため、迷うことはないのですが…。