« 2010年12月 | トップページ | 2011年2月 »

2011年1月

2011年1月30日 (日)

割り勘計算機(3)

今の状況はというと、遅々としてすすんでます。

結局、アダプタを作るのに週末+αを消費してしまい、現状はアダプタ経由でListViewにデータを入れるところまでは行きました。

どこに引っかかっていたかというと、まず、ListActivityなるものがあって、最初、これを継承して作り始めたのですが、つまりは、ListAdapterが最初からくっついてるActivityです。これを使うと、アダプタを指定するだけでListViewが使えたりします。

じゃぁ、ListAdapterはどうやってListViewにセットされるかといえば、idがandroid.R.id.listを持っているもの、と決まっているようです。ListViewを作っただけではだめで、このidを上記の値にする必要があります。これに気がつくのに結構時間掛かってしまいました。

で、今回のアプリはListViewを2個持つ予定なのでこれは使えないということになり、じゃぁどうするのよ?ということになって、結局、xmlに普通にユニークなidつけたListViewをつくり、それをfindViewByIdして、それにsetAdapterすればいいという、ごくごく当たり前な結論に達しました。急がば回れ、そういうことです。

次に問題になったのが、getViewがさっぱり呼ばれない。これもかなりはまったのですが、結局、Adapterのコンストラクタの中でsuperのコンストラクタを呼ぶのですが、これの第3要素にArrayを渡さなければいけない。というのが原因でした。まぁ、分かってみればその通りなんですけどね。

さて、その次問題になるのがレイアウトです。できれば2つのListViewでカラムをそろえたいところです。当初、TableLayoutでやっていたのですが、どうも、全体をひとつのTableLayoutにして、ListViewの個々のViewにTableRowだけしか作らないというのは許されないようです。

アダプタのgetViewでTableRowをインフレートするところまではうまくいくのですが、ListViewが子Viewの高さを測ろうとするところでNullPointerExceptionになります。
TableRowのレイアウトに高さを固定で入れたりしたのですが、やっぱりだめでした。なんかうまくやる方法があるのかもしれませんが、これ以上かまってられないのでLinearLayoutで行くことにしました。

そんなこんなで、現状はプログラム中でセットしたデータを画面に表示できた、という段階です。明日以降にコールバックつけて、次の週末までにはなんとか形にしたいと思っています。いまだに、どうやってデータを入れるのか具体的に、つまりは、TextViewをEditTextに変えるのを本当に使うのか真剣に考えてなかったりするのですが。

中華Padを買った

土曜の朝にインターネットを彷徨っていたら、なぜかシンセンの工場にたどり着いた。

開発用、兼DLNAのコントローラ用に一台今の電話以外のものがほしいと思っていたので、直販でオーダーすることにした。

買ったのは7インチの2.1が搭載されたモデルで、flacを含めた各種オーディオCODEC対応で、HDMIもついてるやつです。本体と送料で合計$190。これでちゃんとしたものが届くならやすいでしょう。

2011年1月27日 (木)

EditTextとTextViewの切り替え

計算機からちょっと脱線です。

UIのデザインについて。

数値の項目が並んでいて、そのどれかを変更したいような場合、どういうUIが使いやすいかという話です。

割り勘計算機の場合、各項は列になっているので、列に変更ボタンをつけて、そこからダイアログを呼び出すというやり方が考えられます。しかし、これだとダイアログが出ている間は全体は見渡せないですね。
では、入力項目を全部EditTextにして並べたらどうえしょうか。これだと、どこにフォーカスがあるのか分かりづらいですよね。フォーカスしているBoxに色をつけたりすればいいのかもしれませんが。それにしてもどこか触るたびにフォーカスしてしまうので、あまり使い易い気がしません。

じゃぁ、普段はTextViewで、クリックしたら編集できるようになるのはどうよ?と思ったのですが、そういうプログラムのサンプルは見つけられませんでした。なので、ちょっと書いて試してみました。

問題は、Viewが作られるのはsetContentViewなりが呼ばれた時で、EditTextとTextViewが同時に存在していないということは、コールバックの登録も一度に済ませることはできないということです。つまり、TextViewがクリックされたらonClickの中でEditTextを作ってOnKeyListenerを登録する必要があり、EditTextで編集が確定したらTextViewを作ってOnClickListenerを登録する必要があります。よくある、setOnClickListenerの中でOnClickListenerをnewしているようなコードの場合、その中のOnClickで相手のコールバックをセットする必要があり、その中でリスナを新たに作って、コールバックを登録するわけですが、そのコールバックでさらに元のViewのリスナを作って、コールバックに...、という無限地獄に堕ちてしまうわけです。

どうすればいいのかEclipse先生と相談しながら作ったのが以下です。

package com.example.FlipboxSample;

import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnKeyListener;
import android.widget.EditText;
import android.widget.TextView;

public class FlipboxSample extends Activity {
    private TextView mTextView01 ;
    private EditText mEditText01 ;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.textview);
    
        mTextView01 = (TextView) findViewById(R.id.TextView01);
        mTextView01.setOnClickListener(textview01OnClickListener);
    
    }
    private OnKeyListener medittext01OnKeyListener = new OnKeyListener() { 
    	public boolean onKey (View v,int keyCode, KeyEvent event){
    		if ((event.getAction() == KeyEvent.ACTION_DOWN) &&
    			(keyCode == KeyEvent.KEYCODE_ENTER)	){
    			String text = mEditText01.getText().toString();
    			setContentView(R.layout.textview);
    			mTextView01 =(TextView)findViewById(R.id.TextView01);
    			mTextView01.setText(text);
    			mTextView01.setOnClickListener(textview01OnClickListener);
    			return true;
    		}
    		return false;
		};
	};
	private OnClickListener textview01OnClickListener = new OnClickListener() {
		public void onClick (View v){
			String text;
			text = mTextView01.getText().toString();
			setContentView(R.layout.edittext);
			mEditText01 = (EditText)findViewById(R.id.EditText01);
			mEditText01.setText(text);
			mEditText01.setOnKeyListener(medittext01OnKeyListener);
		};
	};
} //end of Activity

これで、クリックすればEditTextになって、Enter押せばTextviewに戻るように動くんですが、メンテナンス性悪そうです。
今回の計算機だと、ListViewのAdapterにこれ相当のものを入れることになるわけで、どうなることやら。
なお、ちょっとインデントがずれているのは、SVNに入れて、SVNのWebインタフェースから見たらこうなってました。まぁ、ご愛嬌ということで。

割り勘計算機(2)

ということで、前回の続きです。

現実に則したもう少し複雑な計算ができるクラスを作ります。

具体的には、

条件が違うグループを内包している。
グループをまたがって集計できる。
グループの追加、削除、変更ができる。

という機能があればよさそうですね。これらを組み込んだComplexWarikanクラスを作ってみましょう。

class ComplexWarikan extends Warikan {
	private int actualNubmer ;
	private int totalDept;
	private int payment;
	
	private ArrayList DiscountGroup;
	private ArrayList FixedGroup;
	
	public void addDiscountGroup (int number, int discount){
		DiscountGroup.add(new DiscountWarikan());
		int pos = DiscountGroup.size()-1;
		DiscountGroup.get(pos).setNumber(number);
		DiscountGroup.get(pos).setDiscount(discount);
	}
	public void modDiscountGroup(int pos,int number, int discount){
		DiscountGroup.get(pos).setNumber(number);
		DiscountGroup.get(pos).setDiscount(discount);
	}
	public void removeDiscountGroup(int pos){
		DiscountGroup.remove(pos);
	}

まず、値引きグループと定額グループを入れるArrayListを作ります。そして、それらにクラスを追加したり変更したりするメソッドを用意します。計算式そのものはDiscountWarikanなり、FixedWarikanなりにすでにあるので、金額をセットすれば必要な計算はクラスがやります。
グループを2種類に分けているのは、設定が分かれているUIの方が使いやすそうだから、です。混在させてしまうこともできるのですが、わざわざ凝ったことをして使いにくくする必要もないので別にしています。

とりあえず、定額グループの内容はほぼ同じなのでカットして、最後の集計です。とはいっても、計算というほどのことはなく、ただ、足し算するだけです。最後に通常価格の支払いを計算しておしまい。実際にはグループに反映させなければいけないのですが、それはUIの機能なので、Viewを埋めるときにつくることにします。

	private void calcTotalDebt(){
		// get sum of debt
		// that's total amount of getDept()
		int debt = 0;
		for	(int i=0 ; i<FixedGroup.size() ; i++ ){
			debt += FixedGroup.get(i).getDebt() ;
		}
		for	(int i=0 ; i<DiscountGroup.size() ; i++ ){
			debt += DiscountGroup.get(i).getDebt() ;
		}
		totalDept = debt;
	}

	private void calcActualNumber() {
		// count person who joined Warikan.
		// if class report isWarikan=false, 
		// they don't join Warikan
		int number =0;
		for (int i=0; i<DiscountGroup.size();i++){
			if(DiscountGroup.get(i).isWarikan()) {
			} else {
				number += DiscountGroup.get(i).getNumber();
			}
		}
		for (int i=0; i<FixedGroup.size();i++){
			if(FixedGroup.get(i).isWarikan()) {
			} else {
				number += FixedGroup.get(i).getNumber();
			}
		}
		actualNubmer =number;
	}
	public int getPayment() {
		// so, we are going to calc payment for this Warikan.
		calcTotalDebt();
		calcActualNumber();
		payment = (int) Math.ceil((double)(totalpayment+totalDept)/actualNubmer/roundup)*roundup;
		return payment;
	}
とりあえず、Javaっぽくなってきました。ただ、このコード、まだUIから駆動してないので、なんか間違いがあるかもしれません。あしからず。

2011年1月25日 (火)

割り勘計算機

さて、割り勘計算機です。が、コードを書く前にモデル化しましょう。

まず、割り勘ですが、文章であらわすと、支払い総額に対して各人の支払いが均等になるように請求すること。ですね。

これをクラスにすると

class Warikan extends Object{
  private int number;
  private int totalpayment;
  private int roundup = 100;

  public void setNumber(int n){
    number = n;
  }
  public void setTotalpayment(int total) {
    totalpayment=total;
  }
  public int getPayment(){
    return (int) Math.ceil((double)totalpayment/number/roundup)*roundup;
    }
}

こんな感じなわけです。払いの総額があって、人数があって、たいていはきりのいい額をみんなで出します。が、現実の世の中はこんなにシンプルではありません。

どうなっているかというと、

  1. 立場に応じて額の支払い額の増減がある。
  2. 立場に応じて(0を含む)固定額を支払えばいい場合がある。

というものが主なものですね。つまり、割り勘といっても、中は複数のグループに分割されているのです。

1.でよくあるのは下心満載なフェミニストな男性がよくやる、女性は割引というやつです。

では、まずこれをモデル化しましょう。

割引というのはどういうことかというと、全体の払いに対して負債を作るということです。つまり、男5人、女5人の10人で合計10,000円払う必要があるケースで、女性は500円割引きと決めたとします。ということは全体の支払い額の目標が500*5人分の2,500円増えて12,500円になったということです。
割引の無い男性の支払い額は1,250円、女性は1,250円から500円割り引いて750円です。これで、トータルの払いはやっぱり10,000円です。

このクラスは、さっきのWarikanクラスを継承して表現すると

class DiscountWarikan extends Warikan {
  private int discount ;
  private int number;

  public int getDept(){
    return discount*number;
  }
  public void setDiscount(int d){
    discount=d;
  }
  public int getPayment(int actualPayment) {
    return actualPayment - discount;
  }
}

こんな感じです。getPayment()のところは、このクラスだけでは求めることができないので、とりあえず正規の支払い額というのは教えてもらうことにしています。もちろん、他の人より多く払ってくれる太っ腹な上司というのは差額がマイナスな人として表現できます。

さて、次は2.の定額な人です。このモデル化ですが、実は、定額ということは割り勘ではないのです。つまり、変な話ですが、Warikanクラスにこの人本当に割り勘?という値を返すメソッドを作ります。そして、負債を減らす代わりに割り勘には参加しない人として表現します。

こんな感じです。

class FixedWarikan extends Warikan {
  private int number ;
  private int payment;

  public boolean isWarikan() {
    return false ;
  }
  public int getPayment(){
    return payment;
  }
  public void setFixpayment(int p) {
    payment = p;
  }
  public int getDept() {
    return - number*payment;
  }
}

そして、これらの割り勘グループを複数もった、現実の割り勘クラスというのを作って、

割り勘金額=(支払い総額+負債)/真の割り勘参加者

という形で一人当たりの支払い額を計算し、それを各グループに反映させて各グループの支払い額を求めれば出来上がりです。現実に即したWarikanクラスについては次回に。

なお、ここではモデルの説明に必要なメソッドしか書きませんでしたが、実際にはUIに値を提供するために各種ゲッタが必要なので、コードはもっと長くなります。

2011年1月24日 (月)

充電忘れアプリ完成

とりあえず、できました。

音を出すのは思っていたよりてこずりましたが。なにが原因かというと、

まず、ステータスを完全に指定していなかった。
BATTERY_STATUSには充電中のほかに満充電というステータスがあるのですが、満充電のほうを取っていませんでした。なので、100%になると突然アラームが鳴り出すことになってしまいました。

メディアプレイヤーのステートを理解していなかった
MediaPlayerはファイルを指定すれば再生してくれるのですが、実際に再生する前にファイルをロードして準備するという手続きを踏む必要があります。音を鳴らす段階でこれらをすべてやっていたのですが、そうすると、ボタンのコールバックなり、onPause()なり、onStop()なりで音を止めようとするとき、今Playerがセットアップされているかを知っている必要があります。それが分かるまで、結構Exceptionをもらいました。結局、onCreate()でprepare()までやっておいて、レシーバーのコールバックではstart()するだけになりました。
でも、この辺りはもう少しすっきりさせたいところです。

あとは、Preferenceの画面でsummaryにリングトーンの名前を出すようにしたり、TimePickerDialogを24時間指定にするかどうかを設定&保存できるようにしたり。諸々で1.5日ほど掛かりました。

とりあえず、これでしばらく使ってみて、調整していこうと思います。スタイルなども調整して、もう少しかっこよくしたい気持ちもあるのですが、マーケットに出すわけでもなし、当面優先順位は低いです。

次のネタを考えていたのですが、予告でJavaっぽくと言った手前、サラリーマン生活にありがちなツールとして、割勘電卓をJavaっぽく作ってみたいと思います。

2011年1月23日 (日)

転生

新しいパッチがあたって連日メンテしていたようですが、今日ログインしたらアバターを作り直すことになっていた。

ようやく、以前からCCPが言っていたステーションの中を歩ける、ということは顔写真だけじゃない全身アバターを作る必要があるよね。そんなわけでアバター作れといわれたのかと思ったら、ステーションはまだ歩けないようだった。

とりあえず、1stはカメラ移動できるのわからなかったので真正面の写真になってしまった。これ、作り直すのに$20だかかかるのかな?練習しないと気に入ったアバターできないし1回くらい無料にして欲しい。

その後、新しいImportantミッションが来たので受けてみた。ドローン相手なんだけど、いくら潰しても終わらない。戦艦の残骸がいたるところに散乱している。どうやら、全滅させる手前でステーションを壊さなければいけないらしい。それに気がついたらということでようやく終わった。

そんなこんなで、就寝直前までドローンと遊んでいたのでAndroidのほうの記事は明日にでも書きます。アプリケーションは(自分で使うレベルでは)完成しました。

2011年1月22日 (土)

かわいい女(村上春樹版)

朝、通勤の電車を乗り換えなくても座れたので時間ができた。

時間があると駅の本屋によって時間をつぶす。たいていはコンピュータ関連のコーナーに行って、それからオーディオビジュアル関連の雑誌コーナーを回る。数日前もやっぱり早く着いたので出たばかりのSDをチェックした。けど、今回はパスすることにした。

ということで、一般の小説のコーナーに行くことにした。そうしたら、村上春樹氏のチャンドラー訳第3弾、かわいい女が置いてあった。まだ、前に買った、「キャッチャー・イン・ザ・ライ」も読み終わってないけど、チャンドラー訳があるのに放置して帰るわけにも行かないので手にとってレジへ行った。なぜ、キャッチャー・イン・ザ・ライか、というと、コンピュータ関連技術者が読むべき小説とかなんとかいうリストに入っていたから。でも、いまのところその理由は見つけられないし、内容が退屈なのでほとんど読んでない。RyeがLieの掛けことばなんだということは段々分かってきたけど。

それはさておき、最近、こんなことが多い。第2弾の「さようなら、いとしい人よ」もどこかの本屋で見つけて突然買ったものだ。どうして、こう、衝動買いするのかといえば、Amazonで買わないからお勧めに出なくて、お勧めに出ないからAmazonで買わずに本屋で買う。まったく持っていいことだ。人生やっぱり、偶然の出会いというのは必要だ。これ、もっていますに登録したらきっとお勧めの先頭ページは村上春樹で埋まるだろう。それに、こんな本までAmazonで買ったら街の本屋が無くなってしまう。

でも、リンクは貼ります。:-p

あ、読むべきかどうかは分からないけど、自分が影響を受けた本といえば、一番目はかもめのジョナサン。で、二番目は長いお別れ。

キャッチャー・イン・ザ・ライを買った時に隣にあった本。

そして、一応これも

2011年1月18日 (火)

つくるJukebox(3)

少し前にやって、ショックのあまり記事をかけなかったのですが、

ようやく記事にする気力が整いました。

ええと、scsi-target-utilsのCDROMデバイスはaudioコマンドを扱えるというプロファイルをもっていません。どういうことかというと、ISO形式のデータROM専用ということです。Windowsだと、音楽CDはTOCを読んでWAVファイルがあるようにマウントできますが、tgtdにはというか、Linuxのドライバそのものにそういった機能が無いということです。

今のDVDドライブでcdparanoiaなどのツールを使えば音楽CDのイメージというものを作り出すことはできます。不思議に思ったので中を見たのですが、cdparanoiaもSCSI Generic Deviceにioctlで直接SCSIコマンドを発行しているようです。

カーネルのソースはまだ調べていないのですが、tgtdはDVDROMとDVD-plusのプロファイルしかサポートしていません。iso形式のバッキングストアが指定された場合はDVDROM、そうでない場合はDVD-plusとして動くように作られているようです。実際、音楽CDイメージをバッキングストアに指定したドライブをWindowsからiSCSIでマウントするとRWデバイスのように振舞います。確かに、実デバイスはメディアの種別を判定できるかもしれませんが、HDDのファイルからはメディア種別は取れないので、妥当な仕様なのでしょう。

ちょっと困ったことになってしまいました。自分でパッチ当てて、書き込み機能を捨てて音楽CD用プロファイルを返すように改造しようかとも思うのですが、Androidの相手で手一杯なので進められそうな状況にないです。そろそろCentOS6が出そうな状況でもあることですし、できれば今のFedoraをCentOSに入れ替えてからやることにします。

2011年1月17日 (月)

Eclipseと私

なんか、Eclipseはエライ!みたいなことばかり書いていますが、初心者が使うとそれなりにつまづくところはありますよね。

これまでにつまずいたところを、恥ずかしながらご紹介したいと思います。

  1. UACと相性が悪い
  2. 前にも書きましたが、開発環境にWindows7を使っています。Vista以降には、そう、悪名高い?UACというのがあります。具体的に何が問題かというと、AndroidSDK、ADBを入れるとEclipseからSDKマネージャが呼び出せるのですが、実際にSDKマネージャがアップデートをインストールしようとしてもうまくファイルを更新できません。たぶんUACに引っかかっているのでしょう。SDKマネージャをスタートメニュから管理者モードで呼び出せばちゃんとアップデートできるので、私はそうしています。
    また、プロジェクトの保存にSVNを使っているのは以前ご紹介したとおりですが、先日、SVNのプラグインが使えなくなりました。少し前にSDKをアップデートしていたら、Windowsが、このアプリ(=Eclipse)は互換モードで使ったほうがいいよ?といったのでそうしたのですが、結局、互換モードを止めなければSVNプラグインは動きませんでした。内部的なことはわかりませんが、UACのことはあまり考慮されていないようです。ちなみに、私の環境ではJavaも、SDKも、\Program Files (x86)の中にあります。それもあってUACはバリバリ効きます。でも、UACを使わないというのは、rootで作業すれば権限なんて気にしなくていいと言っているのと同義なので、まったく賛成できません。

  3. コピペに注意

    今回、アプリを作っている最中にR.id.*やR.rayout.*がまったく認識できなくなってしまい、困り果てたことがあります。これ、デバッグに非常に時間かかりました。何が悪かったかというと、APIDEMOからコードをコピーした際に、気を利かせてimport apidemo.Rだかを読み込む設定を自動で追加してくれたのが仇となったのでした。つまり、クラスRはAPIDEMOから参照されるようになり、自分で定義したRはまったく見向きもされない状態だったわけです。このimportを消したらちゃんと動くようになりました。でも、親切すぎです。わかってみれば当然なのですが、素人が気がつくには、ある種ひらめきのようなものが必要です。

それでも、カーソル当てれば解決策を提示してくれるEclipseなしではとても開発できる気がしません。まぁ、理解していないとどれを選べばいいかわからない場合も多いのですが、だからこそ、Javaの文法、規則より根本的な設計に時間を割くことができるようになるわけで、もう手放せないと思います。

2011年1月16日 (日)

アプリ作成中

昨日書いた初アプリですが、大体形になってきました。

現状、プレファレンス画面はリングトーンを選ぶだけですが、できました。メインからの遷移もちゃんとできたし、項目を増やすにしてもxmlを書き足せばいいだけなので変更はほとんどありません。

音を出す部分ですが、BroadcastReceiverをつけて、バッテリステータスを取るのも動きました。あとは、音を出す処理を別スレッドにして、一定時間鳴らす、ステータスが変わったら止める。くらいをつくれば出来上がるでしょう。

そして、メイン画面ですが、PendingIntentをつくって、発行依頼し、Activityが起動するようになりました。当初、ManufestにActivityを書いていなくて、起動せず、あせりましたが。今はデバッグのため指定時刻ではなく、TextViewのonClickから1分後に起動するよう指定していますが、そろそろ、時刻に戻して実機テストに移れる段階に来ていると思います。
残っていた、TimePickerの呼び出しと設定値の保存も、APIDEMOから個別に設定を書き込む例を引っ張ってきて保存するようにできました。TimePickerが返すHourofDayとMinuteの値をPreferenceManagerを使って保存しています。PreferenceManagerはActivityのメンバなので、メインのActivityの値はその内で処理していて、設定関連がまとまっていないのが、なんかすっきりしないのですが。そのほか、最初の値がソースに直に書いてあったりといったことはあるのですが、動作するかという面ではほぼ出来上がりです。

未完成な音を鳴らすスレッドも、あと1-2日あればできそうです。

結局のところ、APIDEMOのソースとEclipseがあれば、必要な処理を切り貼りして、AndroidのAPIを組み立てる程度のプログラムは素人がやっても1週間程度で出来上がってしまうということです。昔昔に、Motifのメニュー構造をゴリゴリ書いていたのとは隔世の感があります(あー、正確には私は書いている人を見ていただけです)。カーソルを合わせれば、どう直せばいいか教えてくれるEclipseの力は偉大ですね。

まぁ、ロジック部分をJavaらしく作るにはそれなりの技術が要るのでしょうが、それはJava全般に言える、あるいはプログラミング共通の課題で、Androidに限ったことではないですからね。現状のマーケットを見る限り、SDKに依存せずに高度な処理をこなすアプリというものはそうそうないようですし。次はもう少しロジックのあるJavaっぽいのを行って見たいと思います。
構想はあるのですが、とりあえず、こっちを動くようにしてから取り掛かりたいと思います。

朝起きたら雪だった

朝、いつものように5時にラジオが鳴り出した。

今日は、プラネタリウムクリエイターの大平さんがインタビューに答えていた。

とりあえず、布団を抜け出したが、今日はやけに寒い。ふと外を見ると世界が白かった。

!雪がふってやがる。まだ1月だというのに。それに、3月ごろに降るべた雪じゃなくてさらさらな雪だ。

雪が降ると最初に思いつくこと、といえば、寒いから布団へ戻ろう、でもなく、新雪の駐車場でくるくる回ろう、でもなく、とにかく除けなければ、という感覚だ。なんでだろうね、だけど、とにかく外へ出て雪掻きをする。まぁ、さらさらだし、1cm程度しか積もってないから、竹ほうきで掃けばなんとかなる。

とりあえず、エントランス周辺と車の出入りに必要な路面を掃いて引き上げる。

雪か、”どうして雪がふるの?”というとやっぱりこれだ。

2011年1月15日 (土)

初めてのアプリケーション

さて、ここのところご無沙汰でした。

これでも社会人なので昼間は会社に居ます。(必ずしも仕事をしているわけではないですが)
なので、平日はそうそう進捗はないです。

週末になって、とにかくアプリケーションと呼べるだけのものを作ろうということでまたEclipseに向かいました。初めてのアプリケーションのお題としては、とりあえず、自分が欲しいと思うもの、ということで、バッテリの充電忘れを教えてくれるアラームタイマということにしました。

初めてだし、どうせ周回遅れで始めたのでそれほど急ぐくともないでしょう。なので、それほど難しくないもの、しかし、それなりに実用になるもの。ということで決めたのですが、実用になる、という点でかなりの要素を取り入れなければいけませんね。

まず、設定の保存。PreferenceActivityなるものがあって、xmlにメニュー構成を書くとほとんどプログラミングなしで設定画面を作ってくれるのですが、問題は、設定できり機能にバリエーションが乏しいということですね。できれば、設定時刻を呼び出すダイアログもこれで作りたかったのですが、残念ながらTimePickerDialogのPreferenceは無いようです。

APIDEMOにはAdvancedなPerferenceの作り方のサンプルもあるのですが、なにやら、自動生成された画面のidを見つけ出して、自分でコールバックを設定するようです。ちょっと敷居が高いですね。こればかりにかかわっているわけにも行かないので別途値をセットするメンバを作る方針でとりあえずは行きたいと思います。

そして、バッテリが充電されているかのチェック。これはかなり例があるのでそれほど難しくはないでしょう。実際、BroadcastListnerを動かしてみましたが、ちゃんと取れました。onCreateでListenerを登録すれば、最初に現在の状態を返してくれるらしいので、アラームActivityの中でListenerを登録して、もらったBroadcastを判定するようにすれば、常に状態を保存しなくてもなんとかなりそうです。

あとは、アラームをセットする画面と、アラーム時刻になったらアラームを鳴らすアクティビティがあればアプリケーションとして成り立ちます。

アラームを鳴らすのはintentでアクティビティを呼び出せばできるでしょう。しかし、これだと、何かしているときにアラーム時刻がやってくると画面が突然変わります。サービスを使えば画面が変わることはないのでしょうが、今度は止めるのに手間どりそうです。充電中であったら鳴らさないのだし、とりあえず、Activityでやってみましょう。

という方針で作り始めました。とりえあず、アラーム音を選ぶRingtonePreferenceだけがある設定画面を作って、メインのActivityでmenuキーが押されたときに呼び出されるところまではできました。残念ながら、エミュレータのリングトーンは鳴りませんでしたが。

明日は、アラームをセットする処理を作って、スタブのアラームActivityを呼び出すようにすることにします。とりあえず、その辺りまでは行きたいですね。

2011年1月10日 (月)

ヨーダの教え

Do, or do not. There is no try.

いい言葉ですね。でも、今回ばかりは教えに背いてしまいました。

なんの話かというと、Andriodチュートリアルの虫とりがようやく終わりました

起動すると、突然アプリケーションが強制終了させられていました。表示してる関数の中をいろいろ調べたりしていたのですが、ソースレベルで追うだけではどこが悪いかさっぱりわかりません。

やっぱり、デバッグは動いているプログラムに聞くのが一番ということでtry-catchやら、Log出力やらいろいろやって、結局のところTextViewのidからクラスを作っているところが悪いらしいというとことまではたどり着きました。

ええ、やっぱりtry-catchは必要でした。ヨーダ先生、ごめんなさい。

じゃぁ、なんでfindViewById()が失敗するかというと、なんと、rayout.xmlの中のTextViewのidのタグがandroid:idではなくてandroid.idになってました。(コロンとピリオドの打ち間違い)

うーん、レイアウトエディタって、中のデータの検証はしないの?それとも私がエラーを見落としたのかな。

まぁ、そんなこんなで、寄り道したけどその分収穫はあったのでよしとしましょう。

つくるJukebox(2)

前回作ったiSCSI Jukeboxですが、リブートしたら消えました。

信じられないのですが、tgtadmは入力されたコマンドを使ってターゲットをセットアップしますが、それはtgtdと通信してセットアップするのであって、ファイルのような永続的なものが残るわけではないのです。
なので、リブートすれば設定は消えてしまいます。

どうやら、設定を保存する目的のためにtarget-adminというコマンドがあって、これでxmlに書き出しなさいということのようなのですが、このコマンド、チェンジャ関連のパラメタは一切生成しません。どうやら、target-adminというのがscsi-target作成当初からあったもので、今はもうメンテナンスされていないというのが現実のようです。

それでも、ディストリビューションの設定としては、target-adminでxmlを作り、それを起動時に読み込ませるというのが本来の手続きのようです。なんか、この適当さにiSCSIがなぜここまで一般化しないか、その理由を見た気がしました。

まぁ、ガタガタ言っても仕方ないので、ブート時に必要なtgtadmをまとめて叩くように起動スクリプトを変更することにしましょう。チェンジャのスロット設定さえtgtadmなので、結構面倒ですが。

2011年1月 9日 (日)

KVMとAFT

KVM(というかXen)のimg形式のファイルをファイルシステムとしてマウントするには

ちょっとやってみたくて調べました。loopback mountするときにoffsetを指定すればいいそうです。

# mount -o loop,offset=32256 some.img /mnt

こうするとマウントできる、ということです。確かにマウントできるんですが、マウントポイントに見えるのは/bootの内容です。

つまり、imgファイルの内容はディスクのイメージそのままなので、ブートセクタなどを読み飛ばして、最初のパーティションが始まるのが32256バイト目ということです。

さて、32256バイト、ちょっと半端ですね。つまり、512バイトセクタが63個で32256バイトです。
勘のいい方は気づいたと思います。つまり、CHSトランスレーションは255トラック63セクタなので、で0シリンダの1トラックの最初のセクタが64番目のセクタ、つまり、32256バイト目です。

実際、イメージをfdiskで見ると

# fdisk go200.img

Command (m for help): p

Disk go200.img: 12.9 GB, 12884901888 bytes
255 heads, 63 sectors/track, 1566 cylinders, total 25165824 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000bca53

    Device Boot      Start         End      Blocks   Id  System
go200.img1   *          63      512064      256001   83  Linux
go200.img2          512065    23060639    11274287+  83  Linux
go200.img3        23060640    25157789     1048575   82  Linux swap / Solaris

こんな結果が返ってきます。2番目のパーティションにアクセスしたければ、512065に512をかけて262177280をオフセットに指定すればマウントできます。

さて、さらに勘のいい人はもう気づいたかとおもいます。WDのディスクはAFTという仕様でできていて、ディスクの物理セクタは4096バイトです。そう、このimgファイルをAFTなディスクで使うと、やっぱり性能が劣化するのです。

AFTとは、つまり、見かけのセクタと実際のセクタサイズが違っていて、ディスクの入出力は4096バイト単位ですが、OSからの要求には512バイト単位で答えます。しかし、今日的なOSは4096バイトより小さい単位の入出力を行うことはないので、OSが要求する4096バイトのクラスタがHDDの物理セクタと一致している分には何の問題もありません。
では、違うとどうなるかというと、HDDは2つのセクタを読み出して、それぞれのセクタにまたがった入出力要求を実施して、命令がWriteなら2つのセクタを書き戻します。この動作が、性能が落ちるといわれる原因です。

じゃぁ、imgは全部だめかというと、どのインストーラを使ったかによります。

# fdisk test1.img

Command (m for help): p

Disk test1.img: 8589 MB, 8589934592 bytes
255 heads, 63 sectors/track, 1044 cylinders, total 16777216 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00075096

    Device Boot      Start         End      Blocks   Id  System
test1.img1   *        2048     1026047      512000   83  Linux
test1.img2         1026048    16777215     7875584   8e  Linux LVM

最初のimgはMeegoをインストールしたものですが、こちらはFedora14のimgです。これはちゃんと4k境界にそろえてパーティションが作られています。
そう、このimgをloopback mountするときにはoffsetの値もそのように指定しなければいけません。

Meegoネタは後のために取っておくとして、Meegoのような比較的新しいOSでもCHSトランスレーションそのままです。仮想計算機なので、別のimgをパーティション切って詰め直せばいいのですが。AFT、現状では使いこなすのは結構大変なようです。

2011年1月 8日 (土)

小ネタ:32bitOS用プログラムのコンパイル

某所でiscsi-initというプログラムを見つけました。

この詳細はまた別の機会に書くとしてmake時に引っかかったことについてのメモ。

このiscsi-init、つまりはinitrdの中で呼ぶとrootfsをマウントしてくれるというものなんですが、モノがモノだけに、スタティックリンクなわけです。さらに、自分が64bitOS使ってても、32bitモードで作るほうがいいよね、と思ったのですが、gccのくそ長いhelpからは見つけだせなかったのでwebを漁った内容。

つまり、-m32オプションをつけばいい。MakefileでCFLAGS=を指定するなら、LDFLAGSにも-m32が必要。そうしないと、64bit用のリンカが呼び出されて、オブジェクトの形式が不正といって怒られる。

だけど、リンクするにはライブラリが必要なので、glibc.i686が必要。スタティックリンクしたいならglibc-static.i686も必要

実は、meegoをネットブートにしたいと思って持ってきたのですが、meegoにはそもそもinitrdがありませんでした。高速化のために、実ディスクのinitを直接呼び出すらしいのです。
まぁ、もともとそうだったわけで、先祖帰りというのでしょう。

scsi-target-utilsとmtxで作る仮想CDライブラリ

最近は何でも仮想化するのがはやりで、仮想テープライブラリなどというものまであります。

つまりは、保存する記憶装置はディスクなのですが、インタフェースはテープのそれで、ロボットアームがテープを入れ替える操作もエミュレートして、ディスクの塊をテープライブラリのように見せかけるという装置です。

バックアップ用としては、テープをハンドリングするソフトは世代の管理に一日の長があるので、エンタープライズ向けにはこういうのもいいのでしょう。

個人的にはテープのライブラリには興味はないですが、家に溜まる一方のCDをなんとか仮想ライブラリ装置に入れたいなぁと日ごろから思っていたのでした。

実CDをそのまま掛けかえるジュークボックスもあるにはある(あった?)のですが、全部のCDをライブラリ化するとなると結構な台数が必要にってしまうくらいCDがあるので購入に踏み切ることはありませんでした。

しかし、最近のディスクの低価格化は恐ろしいものがあります。CD1枚が750MBくらいあったとしても、たった0.75GBでしかないわけです。2TBのHDDが8000円そこそこで買えるわけですから、2600枚以上をひとつの箱につめて、そのコストは1枚あたり数円です。

ずーーっと、仮想CDライブラリのソフト、ないかなぁと思って探していたのですが、なんと、身近なところにありました。

きっかけは別件でscsi-target-utilsのメーリングリストを漁っていたときに目に付いたのですが、つまりは、scsi-target-utilsのiSCSIドライバはライブラリのエミュレーションをすることができて、構成さえすればCDライブラリになるのです。ただし、あくまでもSCSI装置の真似をするので、もともとSCSIにできないことはできないという弱点がありますが。これについては後述。

まず、必要なのはscsi-target-utilsとmtx、それにテストするにはiscsi-target-utilsもとりあえずあったほうがいいでしょう。そうです、同じホストにiSCSIのターゲットとイニシエータをセットアップするのです。

さて、詳しい内容は/usr/share/doc/scsi-target-utils*/README.mmcをご覧ください。結構長いのでここに転記するのは止めます。

一連のコマンドを入れてターゲットをセットアップして、iscsiadmでdiscoveryしてloginすると/dev/sg?と/dev/sr?ができます。sgはSCSI genericの略で、テープでもディスクでもない装置はsdなりstというデバイスは作られないので、ロボットアームのような装置はこのsgを使ってアクセスします。sgは定義したLUNの数だけできるので、READMEのとおりにLUNを定義した場合、一番最後のsgデバイスがアームです。

イニシエータがloginした結果としてsr?も作られます。ここからジュークボックスのデータを読み出します。すでにCDが1台付いているPCならsr1が増えているはずです。

さて、適当なisoファイルを持ってきて、その名前をバーコードラベルの名前に指定します。
この、バーコードの内容がそのままディレクトリのファイル名として参照されます。
そして、mtxコマンドをつかってドライブにロードさせます。このmtxというのが、ロボットアームの操作コマンドです。
が、実際ロードさせると正しく認識できません。どうやら、バーコードは8文字でないといけないようです。確かにLTOのライブラリなども8文字でバーコードつけてますね。

しかし、今回作ったライブラリは1000スロットにしたので、8文字で中身を識別するのは非常に不便です。理論上の上限は全部のデバイスで65535。つまり、読み出し装置が10台くらあって、6万枚収容のチェンジャをつくることもできます。実際には、mtxが指定するのはバーコードではなくスロット番号なので、これを呼び出すフロントエンド側で、内容を説明する長い名前と、スロットの対応付けをするしかないでしょうね。でも、使いやすそうなフロントはまだ見つかってません。見方を替えれば、こんなに便利なジュークボックス機能がほとんど知られていないのは、この辺りの使いづらさによるのでしょう。iSCSIも一般になじみのあるものだとは言えないですし。

そんなこんなで1000スロットのCDジュークボックスにCDを突っ込んで実CDは倉庫にしまう計画が始動しました。
できれば、ジュークボックスはPCじゃなくて、NASのような装置にやってもらえるととってもうれしいなぁ。なんて夢を見ている今日このごろでした。実は昔使っていて今はほとんど使われていないHDL-GSがあって、そういうのをもっと活かせたらいいなぁと思ってます。(まぁ、このHDL-GSも、いったんディスク外してsshで入れるように中を書き換えてあったりするのですが)

2011年1月 6日 (木)

みかんとマカラン

お約束とおり、新年になってザ・マッカランを開けました

いつもはアイラのくっさいモルトが多いこともあって、マッカランがまろやかに感じます。
まぁ、新年だし、最初くらいハイランドがいいかなということで納得しています。

で、正月に以外な発見をしました。

みかんをつまみにマッカランを飲むのが異様にうまいのです。
もともと、シェリー香のあるフルーティな酒ですが、みかんの甘さとのマッチングは絶妙です。

ぜひお試しください。

箱のデザインがよく変わるマッカランですが、今はオレンジっぽい光沢の箱です。(12年は)

で、例のごとくAmazonのリンクを貼ろうと思ったのですが、なんか、普段買う店よりずいぶんお高いようなのでやめておきます。

LibvirtdのKerberos化(2)

昨日設定したLibvirtdですが、すこぶる調子悪いです。

ディスプレイを開くと少ししてからハングします。どうも、タイミング的にはログインして、デスクトップを表示するあたりで固まります。

中のゲストは動いているし、ssh経由なら固まることは無いのでTCPコネクションに問題があるのだとは思いますが、今のところそれ以上は見当がつきません。

SPICEが動かないといって、Libvirtdのバージョンをあげたのでその辺が影響しているかもしれませんが。

ということで、今日は新しいネタはなしです。

仕込みとしては、iscsi-initとかmeegoとかいろいろあるのですが。

2011年1月 5日 (水)

libvirtdのkerberos化

さて、KVMというかlibvirtですが、毎回パスワードを入れるのに疲れました。

せっかくFreeIPAもあることだし、認証をsasl(kerberos)にすることにします。なぜ、kerberos?え、私の中ではシングルサインオンといえばkerberosですがなにか。

まず、事前準備。ログインユーザをFreeIPAに登録していなければそれを作ります。
注意が必要なのは、一度コマンドでログイン(kinit)しておかないとPreferenceのNetwork Authenticationが設定できません。kinitでログインすると、新しいパスワードを求められます。それまでは暫定パスワードなので認証には使用できません。

作業はipa-clientが導入されていればどこでやってもいいのですが、話を簡単にするため、libvirtdが導入されているマシンでやることにします。なお、ここの例ではkvm.example.comがlibvirtd、ipa.example.comがFreeIPAのサーバです。我が家の構成ではIPAはKVMの中のVMですが、この際細かいことは気にしないことにします。

まず、adminのTGTをとります
# kinit admin
Password for adin@EXAMPLE.COMパスワード

で、ユーザを作ります
# ipa-addgroup -g 500 foo
# ipa-adduser foo
First name: Foo
Last name: Bar
foo successfully added

とりあえず、パスワードなんかも設定したとして、次にサーバ側の設定です。libvirtdのSPNはWikiによればlibvirtらしいので、この名前で登録します。ついでにkeytabもつくりましょう。
# ipa-addservice libvirt/kvm.example.com
# ipa-getkeytab -s ipa.example.com -p libvirt/kvm.example.com -k /etc/libvirt/krb5.tab

そして、諸々の設定ファイルを書き換えます。
# vi /etc/sysconfig/libvirtd
LIBVIRTD_ARGS="--listen"を有効に。他も趣味にあわせてどうぞ。

# vi /etc/libvirt/libvirtd.conf
listen_tcp = 1を有効に。auth_tcp="sasl"に。

# vi /etc/sasl2/libvirt.conf
mech_list:gssapiの行を有効に。

で、必要ならiptablesの設定も変えて、libvirtdを再起動します。

デスクトップにログインし、Network Authenticationを設定したら、Vartual Machine Managerを起動し、新しいコネクションを作ります。
コネクションの種別にSASLを指定してサーバを選択すれば出来上がりです。

これで、画面開くたびにパスワードを入れる煩わしさから開放されます。

参考サイト
http://freeipa.org/docs/1.2/Administration_Guide/en-US/html/
http://ja.wikipedia.org/wiki/Libvirt
http://www.asahi-net.or.jp/~aa4t-nngk/kvm4.html

とりあえず、外から使わないならTLSは必要ないので当面これで行ってみたいと思います。FreeIPAの証明書が片付いたらTLSも設定したいと思います。なので、次回は昨日拾った情報から素敵なジュークボックスの作り方の予定です。

次回予告
scsi-target-utilとmtxでつくるCD/DVDジュークボックス

2011年1月 4日 (火)

模様かえ

ディスクのレイアウトを変更することにしました。

4TBのディスクを/storageとしてマウントしてたのですが、思いのほか使いづらいので思い切ってレイアウト変更することにしました。

どういう点が使いづらいかというと。

  • ディレクトリを作る度にSELinuxのラベル付けをしなければいけない。
    /storageというディレクトリはFedoraについているポリシーには考慮されていません。なので、たとえば、/storage/VMをKVMのイメージ置き場にしようとおもえば、そういうポリシーを追加してラベル付けする必要があります。iSCSIのターゲット用ファイルを置くなら同様にポリシーを、tftpブートするならポリシーを、webサービスするならポリシーを...ということになって、そのたびにfixfilesするのが面倒になってきました。

で、どうしたかというと、4TBを一旦マウント解除して、インストール時にできたLVMのVolumeGroupに突っ込みました。で、そこから必要な分を論理ボリュームとして切り出して割り当てる方針に変えました。これなら、容量が足りないパーティションをすぐ拡張できます。それに、iSCSIの実験でパーティションのバッキングストアがほしくなってもすぐ用意できます。どれかひとつのdiskが壊れると全体に影響しますが。まぁ、必要になったら別のディスクに別のPV作って必要なところだけミラーリング組めばいいでしょう。

当面、/varを新しいパーティションにして1TBに構成してあります。

もともと/varは"/"パーティションの中にあったので/varだけ一旦退避して移動させたのですが、その際にSELinuxのラベルが全部object_tになってしまい、サービスが動かなくなってあせりました。しばらく悩んだ末、fixfiles relabelして動くようになりました。めでたしめでたし。

1/5一部語句修正しました

Master Droid Engineerへの道

昔昔、SWGというゲームがあって(いや、日本から撤退しただけで今もやってるのかも)、StarWarsの世界の人になりきるMMORPGだった。

その中に、R2D2やC-3P0のようなアンドロイドを作る職業というのもあった。見習いから始まってスキルを覚えていくとmasterになるとなんでも作れるようになる。

でも、SWGは1アカウント1キャラしかもてなかったのでドロイドエンジニアは選ばなかったけど。

昔話はおいといて、現状のAndroidの進行状況といえば、いまだにチュートリアルやっています。今は この辺です。なぜに、こんなに遅いかというと、TimePickerのサンプルコードが実行時にエラーになる原因がぜんぜんつかめなかったからです。

その間、SPICEしたりいろいろ逃避していたのでこんな現状です。

さて、チュートリアルの進捗よりどれだけ真実を知ったかという点ではかなり進歩してるとおもってます。ええ、自画自賛というのですが。

真実というのは、つまり、Androidのプロジェクトというのは、新規に作った時点で完成しているということです。当然、何もできないのですが、何も手を加えなくても、何もしないという動作をするという意味では完成しています。
このプログラムに、もともとあるActivityというクラスのメソッドを書き換え、リソースを足して自分の目的とするプログラムを作り出すわけです。やりたいことに対してどこをどう書き換えるかさえ理解できれば、手続きそのものはコヒペとeclipseの力で(たぶん)なんとかなります。

とりあえずは、TimePickerやSpinnerといいったウィジェットの使い方は大体つかめたので、あとは実践ですね。とはいっても、実践のためにはもっともっと覚えなければいけないことがあるのも確かですが。

2011年1月 1日 (土)

libvirtでSPICE

SPICEを動かしてみましょう。

まず、クライアントの準備。SPICEのサイトに説明があります。LinuxはFedoraならyumで導入できます。Windows版もサイトにあるので、インストールすれば動きます。ただ、Windwosのクライアントはインストーラなどはついていないので、自分でクライアントとライブラリを別々にダウンロードしてzipを展開し、両者を1つのフォルダに入れる必要があります。

さて、まずはコマンドラインからqemuを動かします。が、異様に遅い。某サイトからコマンドを写したのですが、そのコマンド、エミュレータにqemu-system-x86をしてます。あー、これソフトウェアエミュレーション?そりゃ遅いわ。コマンド名をqemu-kvmにしたらちゃんと動きました。なお、標準は5924番ポートのようですが、F/Wを開けることをお忘れなく。また、ポート番号を変えることはできるかもしれませんが、SELinuxがenforceだとポートが使えないといってAVCをもらうと思います。そういう意味では、標準の構成でディストリビューションを使う限りにおいてはあまりSELinuxを意識しなくても動きます。

で、次はlibvirtに登録して、Virtual Machine Managerから使えるようにします。さっきのコマンドをファイルに書いて、virsh domxml-from-native qemu-argv spice-cmd.txtすればxmlが出力されます。これを、virsh define 名前すればいいはずなんですが、実際にはxmlを作るところで、qxlという(Xのドライバ)なんか知らんといってエラーになります。
仕方ないのでvgaの定義を削ってxmlをつくり、出来上がったxmlを編集してコマンドラインに入れるようにします。

すると、今度はサウンドドライバの仮想計算機上のPCIスロットとqxlドライバのPCIスロットが競合しているというエラーになります。QEMUはビデオ関連はスロット2を割り当てるのですが、xmlにはビデオドライバは無いことになっているので、そこに仮想サウンドカードが割り当てられてしまったようです。以前どこかで、ハードウェアのスロット割り当てを調整する方法を書いたサイトがあったように思うのですが、私が目にしているxmlはPCIのスロット割り当てに関する項目はありません。domxml-from-nativする際にもう少しオプションが必要なのでしょうか。でも、できればxmlを手でごちゃごちゃ直すよりvirshがqxlドライバの存在を認知してくれて、スロット2に割り当ててくれるほうがありがたいのですが。

Fedoraにインストールされているlibvirtのバージョンは0.8.6で、libvirtのサイトには0.8.9というバージョンがあるようです。今日は時間切れ。rpmになったものもあるようなので、これを明日試すことにします。

オーディオはじめ

あけましておめでとうございます。

さて、年が明けると、なんにでも初がつくのですが、我が家には年始の決まりごとというものはほとんどありません。

そんな中、ほぼ唯一といっていい決まりが、オーディオはじめです。

何をするって、特別なことをするわけではなく、厳かにオーディオと向き合ってCDを聴くのですが、一年の最初にかけるCDというのは決まっています。

ベートーベンの交響曲第5番。そう、「運命」と呼ばれているあの曲です。第一楽章の最初の小節が非常に有名な第5ですが、皆さん、最後まで聴かれたことはありますか?

第2楽章は静かでゆったりとしたチェロにコントラバス、第3楽章は弦も加わって明るい曲、そして第4楽章はかなりにぎやかです。
全般に明るい曲で、交響曲としては少数派な長調の曲であり、C Major、いわゆるC調です。

新年にこれを聴くと、新しい年がいい年になるような、そんな感じの曲です。
指揮にもよりますが、30分程度の曲なのでぜひ一度最後まで聴いてみてください。

私がかけるのは、1990年にテルアビブで録音されたもので、ベルリンフィルとイスラエルフィルの合同によるものです。

ちなみに、この曲が「運命」と呼ばれているのは、弟子がベートーベンに、第一楽章の最初の小節にはどの様な意味があるのですか?と聞いたところ、”運命はこのようにドアをノックする”と答えたというのが由来で、ベートーベンが命名したものではないそうです。

あなたも、運命にドアのノックされてみませんか。

« 2010年12月 | トップページ | 2011年2月 »