2011年12月11日 (日)

視波(Shi-Po)。

 iMacのハードディスクがオシャカになった事は以前書いた通りです。同時にWaveScopeのソースコードも消えました。そこで、もう一度作り直したのがこれです。名前はShi-Po(視波)。読みは一応、中国語読みのつもりです。今度はソースコードだけ公開です。バイナリだけの公開は、ハードディスクおシャカ事件で懲りたので。
「Shi-Po.zip」をダウンロード
右下のパワーボタンをクリックすると、スタートします。現状サンプリングレートはデフォルトの44.1kHz以外はまともに使えないと思います。

| | コメント (0) | トラックバック (0)

2011年10月31日 (月)

みむなもすなるlinuxといふものをMacもしてみむとてするものなり

この間ハードディスクがお亡くなりになりディスク容量を4倍にして復活させました。せっかくだから他のOSを入れようと思って、とりあえずLinuxディストリビューションの一つのSlackware64-13.37を入れてみました。なぜSlackwareかというと、筆者が最初に触れたのがこれだったからです。かれこれ、もう16年前の話です。この頃はこれしかありませんでした。一応これをLinuxで書います。
BSD系にしようかと思ったのですが、MacOSXがBSD系なのとOpenFOAMとか直に使いたかったのと、その他諸々の理由で入れてみました。結構快適です。GTK+の日本語入力の設定で少し躓きましたが解決しました。インプットメソッドはuim+anthyです。Core2Duoでもまだイケると思わせてくれました。

| | コメント (0) | トラックバック (0)

2011年10月27日 (木)

imac(late2006)のハードディスクを換装してみました。

ある日、異様に動作が遅くなって起動できなくなったのであれと思っていたら、ハードディスクがお亡くなりになってしまいました。もう5年ぐらい経つので寿命かなと思いつつ、アップルのサポートに電話して、修理にいくら位かかるのかと尋ねたら最高で4万〜(アタマの4万で〜部分は聞こえなくなってしまいました。)と言われました。どのみち保証も切れているので、この際自分で換装しようと思い立ち、パソコン工房でWesternDigitalの1TBのHDD(Caviar Blue)を購入して換装しました。費用はトルクスドライバー(6、8、10)込みで5000円位でした。既に換装されている方の解説を参考にしたので、詳細は省きますが、所要時間は1時間30分ほど、思ったより簡単でした。ただ、驚いたのが、壊れたHDDを取り出すと横に短い棒が2本にょきっと生えていて、これでHDDを空中に支えるようになってました。一瞬「何じゃコリャッ」と思ったのですが、よく見ると、この棒はトルクスねじとなっていて、確かトルクスドライバーの8か10でまわしたらとれました。換装するときは、この棒を新しいHDDに取り付けて、同じように本体へと取り付けます。また、HDDの横には温度センサが取り付けられていました。粘着性のもので貼付けられていたのですが、あいにくそんなものなかったので、応急処置として、センサーとHDDの間にシリコングリスを塗ってセロハンテープで止めておきました。今のところ問題ないです。
 ところで、HDDを換装したら予想外にも、HDDへのアクセスが多い処理のとき、例えば起動時とか、の動作速度が上がりました。体感速度で、正確には比較できませんが、確かに早くなりました。おそらくHDD内蔵の32MBのキャッシュが効いているのだと思います。ちょっと得した気分になりました。

Kansou


| | コメント (0) | トラックバック (0)

2011年10月17日 (月)

Macで波形観測ソフト作成例(1)〜(仮称)WaveScope

作ってみました。まだ、細部まで出来てないですが、とりあえずアルファバージョンです。下部真ん中のサクランボをクリックすると横にドロワーが出て、サンプルレートや入力デバイス、通常のスコープ、FFT、リサジューなどの表示切り替えが出来ます。サンプルレートはどうも、当方の環境(intel mac late 2006)では固定されているらしくて選択できまないのでテストしていません。もしかしたら、プログラムミスかもしれません。FFTはまだ、表示方法をどうしようか考え中です。現在は横軸を位相にして表示しています。「WaveScope.app.zip」をダウンロード

| | コメント (0) | トラックバック (0)

2011年9月29日 (木)

Macで波形観測(5)

最新のSDKでcore audioのAPI関数がたくさんdeprecateされています。例えば、AudioHardwareGetPropertyとかAudioDeviceGetPropertyとか、Audio<〜>みたいなのです。代わって、AudioObject<〜>のような関数に統一さている様です。HardwareとかDeviceなどは、AudioObjectPropertyAddress構造体で指定するようになりました。しかし、これが今一よく分からないです。そこで、core audioのサンプルAudioDeviceNotifyをこの新しい方法で書き直した物をアップしておきます。興味がある方は自分でダウンロードして各自で考えてください。なぜなら筆者もまだよく分からないのであしからず。
「AudioDeviceNotify.zip」をダウンロード

| | コメント (0) | トラックバック (0)

2011年7月24日 (日)

Macで波形観測(4)

 今回は予備知識をいくつか書いていきます。まず、このプログラムで使用している音声フォーマットはリニアPCMというフォーマットを使用しています。詳細はいくらでもネット上に転がっているのでそちらを参照してもらうとして要約だけ書きますと、例えば16ビットのリニアPCMというのは、−1.0〜+1.0までの数値を16ビット諧調で表すという事です。すなわち、16ビット整数は65536個の数値を表せますので、-1.0〜+1.0を65536個の階段で区切るという事です。実際には符号つき整数ですので、-32768〜+32767までの数値で表されます。従って、取得された音声データはそのままでは、直接小数値として表すことは出来ません。もしそんな事をすると変な事になります。音声フォーマットは他にもいくつか指定出来ますが、一番簡単というか一般的なのがこのリニアPCMではないかと思います。
 次に、サンプリングレートの単位はHzです。ここでは44.1kHzを使用しています。すなわち、1/44.1=22.6μsの間隔で音声をサンプリングしていきます。ただし、コールバック関数を呼び出すタイミングは、同じである必要はありません。デフォルトでは512個のデータがたまった時点で呼び出されます。すなわち512/44.1=11.6msごとにコールバック関数が呼び出される事になります。ちなみに、データを格納する為に用意するAudioBufferList構造体も、この場合512個のデータを格納する領域が必要になります。また、この値はプログラムで変更出来ます。
 コールバック関数内から、オブジェクト内のメソッドを直接呼び出す事は出来ません。そこで、コールバック関数を設定するときに、後で呼び出したいオブジェクトを渡してやります。具体的には、AURenderCallbackStructのメンバーInputProcRefConにそのオブジェクトのポインタを渡してやります。
 以上、今回はここまで。

| | コメント (0) | トラックバック (0)

2011年7月23日 (土)

Macで波形観測(3)

各メソッドについて説明します。基本的にリファレンス通りなので目新しいものはありません。
(1)(OSStatus)createInputUnit
 AudioUnitを一つ用意します。
(2)(OSStatus)enableIO
 作成したオーディオユニットの入力を有効にし、出力を無効にします。デフォルトでは出力になっています。
(3)(OSStatus)setDefaultInputDeviceAsCurrent
 オーディユニットの入力デバイスを現在のオーディオ入力デバイスに設定します。
(4)(OSStatus)setAudioFormat
 サンプリングレート、データのビット数、データフォーマット等を設定します。
(5)(OSStatus)setCallBackProc
 サンプリングの為のコールバック関数を登録します。
(6)(AudioBufferList *)allocateAudioBufferList:(UInt32)Channels Size:(UInt32)size
 オーディオデータを格納するバッファリストを作成します。データの取得はコールバック関数から、AudioUnitRender関数を呼び出して行います。この関数の引数の一つとして、このメソッドで作成したAudioBufferList構造体を渡します。
(7)(void)drawSignal:(AudioBufferList *)list
 与えられた引数から、信号をグラフとして表示する為のパスを作成します。描画処理はdrawRectメソッドに実装し、setNeedsDisplayメソッドをコールバック関数から呼び出して描画します。
(8)(IBAction)start:(id)sender
 信号取得を開始、停止を行います。AudioOutputUnitStart(InputUnit)で開始、AudioOutputUnitStop(InputUnit)で停止します。
本日はここまで。以下続く。

| | コメント (0) | トラックバック (0)

2011年7月21日 (木)

Macで波形観測(2)

 オシロスコープが買えなくて、身近なものを変わりにしようと思い立ちました。USBインターフェースを持ったPICマイコンでも使おうかと思ったのですが、パソコンのオーディオ入力を使用している方がいらっしゃったので、自分でもやってみようと思い開発を始めました。
 まず、当面の目標は、オーディオデータを取得しグラフに表示する事としました。Macでオーディオ入力を取り扱うにはCoreAudioというフレームワークを使用します。もっともCoreAudio自体は、いろいろなフレームワークの集合なので、誤解無きよう。
 前回も書いたのですが、入力データを取得しそれをグラフに表示するクラスを作成しました。その名も、SignalViewクラスです。このクラスはNSViewクラスを継承したクラスです。と言う訳で、ソースを示します。説明は次回。

//
// SignalView.h
//
// Created by 大野 英 on 11/07/16.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import <Cocoa/Cocoa.h>
#import <AudioUnit/AudioUnit.h>
#import <AudioToolbox/AudioToolbox.h>

@interface SignalView : NSView {
AudioUnit InputUnit;
AudioDeviceID InputDevice;
NSArray *graphPath;
CGContextRef context;
IBOutlet NSButton *_start;
bool austatus;
}
-(OSStatus)createInputUnit;
-(OSStatus)enableIO;
-(OSStatus)setDefaultInputDeviceAsCurrent;
-(OSStatus)setAudioFormat;
-(OSStatus)setCallBackProc;
-(AudioBufferList *)allocateAudioBufferList:(UInt32)Channels Size:(UInt32)size;
-(void)drawSignal:(AudioBufferList *)list;
-(IBAction)start:(id)sender;
@end

//
// SignalView.m
//
// Created by 大野 英 on 11/07/16.
// Copyright 2011 __MyCompanyName__. All rights reserved.
//

#import "SignalView.h"


@implementation SignalView
OSStatus InputProc( void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData
){
SignalView *SELF = (SignalView *)inRefCon;
AudioBufferList *bufferList = [SELF allocateAudioBufferList:1 Size:sizeof(SInt16)*inNumberFrames];
AudioUnitRender(SELF->InputUnit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, bufferList);
[SELF drawSignal:bufferList];
[SELF setNeedsDisplay:YES];
[SELF removeAudioBufferList:bufferList];
return noErr;
};
- (id)initWithFrame:(NSRect)frame {
OSStatus err;

self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
err = [self createInputUnit];
[_start setTitle:@"START"];

if (err) {
return nil;
}
err = [self enableIO];
if (err) {
return nil;
}
err = [self setDefaultInputDeviceAsCurrent];
if (err) {
return nil;
}
err = [self setAudioFormat];
if (err) {
return nil;
}
err = [self setCallBackProc];
if (err) {
return nil;
}
AudioUnitInitialize(InputUnit);
}
return self;
}
-(OSStatus)createInputUnit{
AudioComponentDescription cd;
OSStatus err;
cd.componentType=kAudioUnitType_Output;
cd.componentSubType=kAudioUnitSubType_HALOutput;
cd.componentManufacturer=kAudioUnitManufacturer_Apple;
cd.componentFlags = 0;
cd.componentFlagsMask =0;

AudioComponent com=AudioComponentFindNext(NULL, &cd);
err = AudioComponentInstanceNew(com, &InputUnit);

//err = AudioUnitInitialize(InputUnit);
return err;

}
-(OSStatus)enableIO{
OSStatus err;
UInt32 enableIO=0;
enableIO = 1;
err = AudioUnitSetProperty(InputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &enableIO, sizeof(enableIO));
if (err) {
NSLog(@"Failed Enable Input. ");
return err;
}
enableIO = 0;
err = AudioUnitSetProperty(InputUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, 0, &enableIO, sizeof(enableIO));
if (err) {
NSLog(@"Failed Disable Output. ");
return err;
}
return err;

}

-(OSStatus)setDefaultInputDeviceAsCurrent{
OSStatus err;
UInt32 size = sizeof(AudioDeviceID);
AudioObjectPropertyAddress address;
address.mElement=kAudioObjectPropertyElementMaster;
address.mScope=kAudioObjectPropertyScopeGlobal;
address.mSelector=kAudioHardwarePropertyDefaultInputDevice;
err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &address, 0, NULL, &size, &InputDevice);
if (err) {
NSLog(@"Can't get default input device.\n");
return err;
}
err = AudioUnitSetProperty(InputUnit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &InputDevice, sizeof(InputDevice));
if (err) {
NSLog(@"Can't set default input device.\n");
return err;
}
return err;
}
-(OSStatus)setAudioFormat{
OSStatus err;

AudioStreamBasicDescription audioFormat;
audioFormat.mSampleRate = 44100.00;//44100.00;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel = 16;
audioFormat.mBytesPerPacket = 2;
audioFormat.mBytesPerFrame = 2;

err = AudioUnitSetProperty(InputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output,
1,
&audioFormat,
sizeof(audioFormat));

if (err) {
NSLog(@"Can not set output stream format.\n");
return err;
}
return err;
}
-(OSStatus)setCallBackProc{
OSStatus err;
AURenderCallbackStruct input;
input.inputProc = InputProc;
input.inputProcRefCon = self;

err = AudioUnitSetProperty(
InputUnit,
kAudioOutputUnitProperty_SetInputCallback,
kAudioUnitScope_Global,
0,
&input,
sizeof(input));
if (err) {
NSLog(@"Can not set Input callback proc.\n");
return err;
}
return err;
}

-(AudioBufferList *)allocateAudioBufferList:(UInt32)numChannels Size:(UInt32)size{
AudioBufferList *list;
UInt32 i;

list = (AudioBufferList*)calloc(1, sizeof(AudioBufferList)
+ numChannels * sizeof(AudioBuffer));
if (list == NULL) return NULL;

list->mNumberBuffers = numChannels;

for(i = 0; i < numChannels; ++i) {
list->mBuffers[i].mNumberChannels = 1;
list->mBuffers[i].mDataByteSize = size;
list->mBuffers[i].mData = malloc(size);
if(list->mBuffers[i].mData == NULL) {
[self removeAudioBufferList:list];
return NULL;
}
}

return list;
}

- (void)removeAudioBufferList:(AudioBufferList *)list
{
UInt32 i;

if(list) {
for(i = 0; i < list->mNumberBuffers; i++) {
if (list->mBuffers[i].mData) free(list->mBuffers[i].mData);
}
free(list);
}
}

-(void)drawSignal:(AudioBufferList *)list{
UInt32 frames,i,j;
SInt16 *input;
float signal=0;
NSMutableArray *temp = [NSMutableArray array];
if(graphPath==nil){
graphPath = [NSArray array];
}

for(i=0;i<=list->mNumberBuffers-1;i++){
frames = list->mBuffers[i].mDataByteSize/sizeof(SInt16);
input = list->mBuffers[i].mData;
for(j=0;j signal = (float)input[j];
if (signal >= 0) {
signal=signal/32767;
}else {
signal=signal/32768;
}
NSNumber *sig = [NSNumber numberWithFloat:signal ];
[temp addObject:sig];
//[sig autorelease];
}
}
NSMutableArray *gP = [graphPath mutableCopyWithZone:nil];
[gP addObjectsFromArray:temp];
while ([gP count]>[self bounds].size.width) {
[gP removeObjectAtIndex:0];
}

graphPath = [gP copyWithZone:nil];
[gP release];

}
-(IBAction)start:(id)sender{
if (austatus==0) {
AudioOutputUnitStart(InputUnit);
[_start setTitle:@"STOP"];
austatus = 1;
}else {
AudioOutputUnitStop(InputUnit);
[_start setTitle:@"START"];
austatus = 0;
}


}

- (void)drawRect:(NSRect)dirtyRect {
// Drawing code here.
float signal;

if (context == NULL) {
context = [[NSGraphicsContext currentContext] graphicsPort];
}
CGContextSetRGBFillColor(context, 0, 0, 0, 1);
CGContextFillRect(context, CGRectMake(dirtyRect.origin.x, dirtyRect.origin.y, dirtyRect.size.width, dirtyRect.size.height));
CGContextBeginPath(context);

CGContextMoveToPoint(context, dirtyRect.origin.x, dirtyRect.size.height*0.5);
CGContextAddLineToPoint(context, dirtyRect.size.width, dirtyRect.size.height*0.5);
CGContextSetRGBFillColor(context, 0, 1, 0, 1);
CGContextStrokePath(context);

if (graphPath==nil) {
return;
}
int i=0;

CGContextBeginPath(context);

for(i=0;i<[graphPath count]-1;i++){
signal = [[graphPath objectAtIndex:i] floatValue];
//NSLog(@"%f",signal);
CGContextMoveToPoint(context, (float)i, (signal*0.5+0.5)*dirtyRect.size.height);
signal = [[graphPath objectAtIndex:i+1] floatValue];
//NSLog(@"%f",signal);

CGContextAddLineToPoint(context, (float)(i+1), (signal*0.5+0.5)*dirtyRect.size.height);
}
CGContextSetRGBStrokeColor(context, 0, 1, 0, 1);
CGContextStrokePath(context);

}
@end

 

| | コメント (0) | トラックバック (0)

2011年7月20日 (水)

Macで波形観測(1)。

 最近Macで波形観測をする為のプログラムを書いています。波形の入力は音声入力を使用しました。core audioを使用しました。信号受信、取り出しはビューオブジェクトに受け持たせました。ビューオブジェクトには波形の表示も兼任させました。 これを使って、macをオシロスコープの様に使用して見たいと思います。以降続く。

| | コメント (0) | トラックバック (0)

2011年6月14日 (火)

(多分)X1シリーズ対応。PS/2コネクター仕様のキーボードを繋ぐ〜総集編

 PS/2コネクターのキーボード、PFUのHappy Hacking Keyboard Lite(以下HKB)をSHARPのテレビ事業部が製造販売していた8bitパソコンX1シリーズに繋げた記事のまとめです。記事がバラバラで、分かりにくかったのでひとまとめにします。

<使用機器>
SHARP X1turboZⅢ(CZ-888C)・・・テスト用のターゲット
Microchip PIC12F689・・・PS/2キーボードの信号(スキャンコード)をX1用のキーボードの信号へ変換します。

<開発環境>
MPLAB IDE v8.7・・・PIC用の開発環境。変換プログラム開発に使用。開発言語はC言語(HI-TECH)。

<変換回路>
<回路図>
まず回路図を示します。

Sch2

回路はユニバーサル基板に実装しました。部品一覧を以下に示します。

           
部品名部品点数
Microchip PIC12F6891
抵抗2kΩ
抵抗4.7kΩ1
3端子レギュレータTA7805S1
積層セラミックコンデンサ0.33uF1
積層セラミックコンデンサ0.1uF1
セラロック20MHz1
8pinICソケット1
ユニバーサル基板1
φ3.5ステレオジャック1
φ3.5ステレオケーブル1

<回路の説明>
1.PICマイコン
VDD:電源+5V
VSS:GND
汎用IOピンGP0:X1キーボード信号出力、4.7kΩ抵抗でプルアップ。
     GP1:PS/2キーボードクロック読み取り、2kΩ抵抗でプルアップ。
     GP2:PS/2キーボードスキャン(走査)コード読み取り、2kΩ抵抗でプルアップ。
     GP3:MCLRリセット。
     GP4、5:システムクロック入力(セラロック20MHzを接続)。
2.電源
TA7805S:+5V電源を得る為に使用しました。キーボード、PICマイコン用の電源です。X1本体のキーボード端子からの電源では力不足かもしれなかったので、このような仕様としました。


<変換プログラム仕様>
1.PICマイコンにて、PS/2キーボードからクロック信号を読み取り、それがLOWの時、スキャンコードの信号を読み取ります。
2.スキャンコードの伝送フォーマットは11ビットで、スタートビットやパリティ、ストップビットは無視して、データ部分のみをchar型変数dataに保存します。(read_data関数)。
3.dataをアスキーコードへと変換します。また、シフトキー等が押されていた場合は、char型変数funcに適当な値をセットし、次の入力を待ちます。新しいデータが入力された後対応するアスキーコードへと変換します。(chekcode関数)。
4.x1の伝送フォーマットに従って、キーデータを送信します。
5.送信タイミング用に8ビットタイマーTMR2割り込みを使用しました。これにより50us間隔で割り込みが発生し、50us毎に出力端子GP0に次回の割り込み時に出力される値がchar型変数nextにセットされます。変数nextは、タイマー割り込み発生時に最初に汎用IOレジスタGPIOへ値がコピーされます。
6.キーが離されたとき終端コード0xFFが送信されます。
7.読み取りはGP1端子への入力割り込みを使用しました。GP1端子への信号が変化すると割り込みが発生し、2の手順に従ってスキャンコードが読み取られます。
8.変換テーブルはEEPROMに書き込まれています。0番地からソースコードのOFFSET_ASCIIー2までがスキャンコード、OFFSET_ASCIIからSHIFT_ASCII−2までがASCIIコード、SHIFT_ASCII−2以降がシフトキーが押されたときのコードになります(現時点)。現在はHKB用のスキャンコードにのみ対応していますが、変換テーブルを106キーに対応させれば使用可能と思われます。
9.文字入力(enter、スペース、バックスペース、tab、シフトキーを押しながらの入力も含む)以外は未実装です。

<ソースコード>
ソースコードは以下からダウンロード可能です。
「main.lzh」をダウンロード

<既知の問題>
1.シフトキーが押されてもhu-basicのinkey$(2)の結果に反映されないです。
2.キー入力時に「ポッ」と言う音がします。仕様なのかどうかは不明です。
3.GRPHキーとかカナとかCTRLキーとか押しても無視されます。
4.ノイズの為なのか、時々動作しません。このような場合は電源、他コネクターを全部ぬいて、また、やり直すと動きます。

以上。

| | コメント (1) | トラックバック (0)

«現在休憩中〜ちょっとゾクッとした話。