友人のMacBook ProのバッテリーとSSD交換
友人のMacBook Pro、仕事の都合上数ヶ月放置したことによりバッテリーがご臨終したようで、これをAmazonでポチっておいてくれたら交換してあげるよという話に。
モデルは MacBook Pro (13-inch, Early 2011) MC700J/A でした。
HDDからSSDへの交換はクリーンインストールではなく、MacBook Proに新SSD刺してターゲットディスクモードで起動、旧HDDを外付けHDDケースに入れて、自分のMacに両方接続→Carbon Copy Clonerでディスクまるごとコピーという手順。
Retina以前のMacBook Proはなんでもかんでも自分で交換できてよかったよなぁ。
この頃のMacBook Proは13インチと15インチ両方使ってたので、ことあるごとに裏蓋を開けていじくってたのを思い出した。
- 出版社/メーカー: World Plus / ワールドプラス
- メディア: エレクトロニクス
- この商品を含むブログを見る
Transcend SSD 256GB 2.5インチ SATA3 6Gb/s MLC採用 3年保証 TS256GSSD370S
- 出版社/メーカー: トランセンド・ジャパン
- 発売日: 2015/04/30
- メディア: Personal Computers
- この商品を含むブログ (2件) を見る
Audio UnitでCocoaのCustomViewを使う
前回のサンプルコードをただビルドしただけのSinSynthは、AUホストでプラグインを表示すると「GenericView」で表示されます。パラメータ定義に応じて自動生成される、所謂こういうやつ↓
Custom View (Cocoa View) を使いたい
エフェクターならまだしも、普通ソフトシンセはGenericViewではどうにもできないくらい膨大なパラメータ数になるので、Custom Viewを作る必要がありますね。前回使ったサンプルコードの中に「AudioUnitEffectExample」というものがあって、これはLPFのプラグインでCocoaのCustom Viewが用意されています。AU Instrumentの場合であっても、これを真似すればOKです。
作成手順
SinSynthにCocoaVIewを追加する手順。詳細は「AudioUnitEffectExample」をXcodeで開いて見てもらうとして、必要最低限の要点だけ。
1) SinSynthプロジェクトにTARGETを追加。「OS X -> Framework & Library -> Bundle」
Product Nameは「CocoaUI」とします。
2) TARGET CocoaUIにAUCocoaUIBaseプロトコルのViewFactoryと、NSViewのサブクラスを追加
OuiSinSynth_ViewFactory.h
#import <Cocoa/Cocoa.h> #import <AudioUnit/AUCocoaUIView.h> @class OuiSinSynth_UIView; @interface OuiSinSynth_ViewFactory : NSObject <AUCocoaUIBase> { IBOutlet OuiSinSynth_UIView *uiFreshlyLoadedView; } - (NSString *) description; @end
OuiSinSynth_ViewFactory.m
#import "OuiSinSynth_ViewFactory.h" #import "OuiSinSynth_UIView.h" @implementation OuiSinSynth_ViewFactory - (unsigned) interfaceVersion { return 0; } - (NSString *) description { return @"Demo: Sin Synth"; } - (NSView *)uiViewForAudioUnit:(AudioUnit)inAU withSize:(NSSize)inPreferredSize { if (![[NSBundle bundleForClass:[self class]] loadNibNamed:@"CocoaView" owner:self topLevelObjects:nil]) { NSLog (@"Unable to load nib for view."); return nil; } [uiFreshlyLoadedView setAU:inAU]; NSView *returnView = uiFreshlyLoadedView; uiFreshlyLoadedView = nil; return returnView; } @end
OuiSinSynth_UIView.h
#import <Cocoa/Cocoa.h> #import <AudioUnit/AudioUnit.h> #import <AudioToolbox/AudioToolbox.h> @interface OuiSinSynth_UIView : NSView { AudioUnit mAU; } - (void)setAU:(AudioUnit)inAU; @end
OuiSinSynth_UIView.m
#import "OuiSinSynth_UIView.h" @implementation OuiSinSynth_UIView - (void)setAU:(AudioUnit)inAU { mAU = inAU; } @end
3) CocoaUIにxibファイルを追加。 「OS X -> User Interface View」 ファイル名は「CocoaView.xib」とします。(とりあえずラベルをひとつ載せておく)
4) CocoaView.xibの File's Owner を OuiSinSynth_ViewFactory に変更
Viewの CustomClass を OuiSinSynth_UIView に変更
VIewを OuiSinSynth_ViewFactoryクラスの uiFreshlyLoadedView の IBOutlet に設定
5) SinSynthクラスにUI定義用のメソッド追加
SinSynth.h
class SinSynth : public AUMonotimbralInstrumentBase { public: ***省略*** virtual OSStatus GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void * outData ); virtual OSStatus GetPropertyInfo (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32 & outDataSize, Boolean & outWritable); ***省略***
SinSynth.cpp
***省略*** OSStatus SinSynth::GetPropertyInfo (AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, UInt32 & outDataSize, Boolean & outWritable) { if (inScope == kAudioUnitScope_Global) { switch (inID) { case kAudioUnitProperty_CocoaUI: outWritable = false; outDataSize = sizeof (AudioUnitCocoaViewInfo); return noErr; } } return AUInstrumentBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable); } OSStatus SinSynth::GetProperty(AudioUnitPropertyID inID, AudioUnitScope inScope, AudioUnitElement inElement, void * outData ) { if (inScope == kAudioUnitScope_Global) { switch (inID) { case kAudioUnitProperty_CocoaUI: { CFBundleRef bundle = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.audiounit.sinsynth") ); if (bundle == NULL) { printf("error bundle\n"); return -43; //fnfErr; } CFURLRef bundleURL = CFBundleCopyResourceURL( bundle, CFSTR("CocoaUI"), CFSTR("bundle"), NULL); if (bundleURL == NULL) { printf("error bundle url\n"); return -43; //fnfErr; } CFStringRef className = CFSTR("OuiSinSynth_ViewFactory"); AudioUnitCocoaViewInfo cocoaInfo = { bundleURL, { className } }; *((AudioUnitCocoaViewInfo *)outData) = cocoaInfo; return noErr; } } } return AUInstrumentBase::GetProperty (inID, inScope, inElement, outData); } ***省略***
6) TARGET「SinSynth」のTarget Dependenciesに「CocoaUI」を追加
7) TARGET「SinSynth」にCopy Filesをもうひとつ追加して「CocoaUI.bundle」を選択
8) 以上。ビルドしてAU Labで実行。
プラグイン右上のドロップダウンが「GenericView」になっている場合は、「Demo: Sin Synth」に変更するとCustom Viewが表示されます。
Hello Worldだけでなかなか手間のかかること!
ここまでできればあとは頑張ってUIを作り込むだけ。そっちの方が大変……
- 作者: 熊谷友宏
- 出版社/メーカー: 秀和システム
- 発売日: 2014/04/29
- メディア: 単行本
- この商品を含むブログ (1件) を見る
Audio Unit Instrumentを作る
MacのAudio Unitの作り方を調べていて、サンプルを動かすところまでこぎつけたのでメモ。
開発環境
まず現在の開発環境ですが、
- Mac OS X 10.9.4
- Xcode 5.1.1
- AU Lab 2.2.1
https://www.apple.com/jp/itunes/mastered-for-itunes/
です。
サンプルコードをビルド
Xcodeではずいぶん前のバージョンからAudio Unitプラグインのプロジェクトテンプレートが削除されているので、デベロッパサイトからサンプルコードを持ってきてそれを雛形とします。
https://developer.apple.com/library/mac/samplecode/sc2195/Introduction/Intro.html
(上部の「Download Sample Code」ボタン)
zipを展開してAudioUnitInstrumentExampleのプロジェクトをXcodeで開きます。
この状態でそのまま「Product -> Build」を実行すると、
/Users/(username)/Library/Developer/Xcode/DerivedData/SinSynth-xxxxx/Build/Products/Development/SinSynth.component
のような場所にSinSynth.componentが出力されると思います。
これを
/Users/(username)/Library/Audio/Plug-Ins/Components
にコピーして、LogicなどのDAWを起動すると……
「AU Instruments -> Apple Sample Code -> Sin Synth (Instrument AU)」として選択できるようになり、適当にMIDIノートを入力してみると、無事サイン波が再生されました。
デバッグ環境
ビルド時にComponentsディレクトリへのコピーとAUホストを自動で立ち上げてデバッグできるようにします。
まずTARGETS SinSynthのBuild Phasesに、SinSynth.componentをプラグインディレクトリにコピーする「Copy Files」を追加します
Destination : Absolute Path
Path : $(USER_LIBRARY_DIR)/Audio/Plug-Ins/Components/
次に「Product -> Scheme -> Edit Scheme」を選択して、「Run」の「Executable」をAU Lab.appに変更します。
で、「Product -> Run」すると、AU Labが起動します。初回起動時はAU Labのドキュメントの新規作成ダイアログが表示されると思いますので、ドキュメントを新規作成して「Edit -> Add Audio Unit Instrument...」からSInSynthのトラックを追加します。
あとはAU LabのPreferencesの「Document -> When Launching AU Lab」を「Open a specific document」にして、開発中のプラグインを読み込んだ状態のドキュメントを指定しておけば、次回実行時はすぐさま動作確認できる状態で立ち上がってくれます。
開発中にMIDIキーボードを繋げるのが面倒な場合は、MidiKeysなどの仮想キーボードを使えば、Macだけで手軽にデバッグできますね。
- 作者: アーロンヒレガス,アダムプレブル,Aaron Hillegass,Adam Preble,東京電機大学,東電大=,東京電機大=
- 出版社/メーカー: 東京電機大学出版局
- 発売日: 2014/05/20
- メディア: 単行本
- この商品を含むブログを見る
貴重なCoreAudio本が絶版のようです
iOSのCore Audioについてこれ以上に詳しいものは無かったという貴重な本ですが、いつのまにかAmazonほかどこのネット書店でも在庫なしになっているみたい。
自分もつい先日、欲しかった本が絶版になってて探しても見つからないことがあったので、良い本がひっそりと絶版になってるのは悲しい……
- 作者: 永野哲久
- 出版社/メーカー: ソフトバンククリエイティブ
- 発売日: 2009/11/12
- メディア: 大型本
- 購入: 6人 クリック: 114回
- この商品を含むブログ (25件) を見る
SQL Serverで全角スペースやタブ文字のトリム
そういえばSQL ServerのLTRIM, RTRIMは全角スペースは除去してくれず、T-SQLだけでやろうとしてもなかなかスマートなやり方が無いっぽいんでした。
前回に引き続き、そういうTrimが必要に迫られたのでSQLCLRで作ります。
using System; using System.Data; using System.Data.SqlClient; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; public partial class UserDefinedFunctions { [Microsoft.SqlServer.Server.SqlFunction] public static SqlString Trim(SqlString value) { if (value.IsNull) return value; return new SqlString(value.ToString().Trim()); } };
といってもこれだけ。
C#のTrimと同じ動きが欲しいだけなので、これだけ。
SQL Server 2012 逆引き大全515の極意―データベース構築管理編
- 作者: 長岡秀明
- 出版社/メーカー: 秀和システム
- 発売日: 2012/12
- メディア: 単行本
- この商品を含むブログを見る
SQL ServerでGROUP_CONCATのようなものを使う
SQL Serverには、MySQLで言うところの GROUP_CONCAT のような文字列を結合してくれる集計関数がなくて、T-SQLでユーザ定義の集計関数を作ることもできません。でもちょっと必要に迫られたのでSQL CLRのユーザ定義関数を作ってみました。(SQLCLRは滅多に使わないのでやり方をほとんど忘れてしまっていました…)
ひとつポイントは、nvarchar(4000)のサイズを超える結果が返ってくる可能性がある場合、
public void Accumulate([SqlFacet(MaxSize=-1)]SqlString value, SqlString delimiter)
[return: SqlFacet(MaxSize = -1)] public SqlString Terminate()
というふうに SqlFacet(MaxSize=-1) のアトリビュートを付けると、引数と戻り値をnvarchar(max)にできるようです。
あと、
[SqlUserDefinedAggregate( Format.UserDefined, //use clr serialization to serialize the intermediate result IsInvariantToNulls = true, //optimizer property IsInvariantToDuplicates = false, //optimizer property IsInvariantToOrder = false, //optimizer property MaxByteSize = -1) //maximum size in bytes of persisted value ]
の、 MaxByteSize = -1 の部分。
SqlFacet(MaxSize=-1)を付けないただの SqlString を使うと、nvarchar(4000)として作られてしまうので、大きい結果を返すことはできません。
以下コード全文。
using System; using System.Data; using Microsoft.SqlServer.Server; using System.Data.SqlTypes; using System.IO; using System.Text; using System.Collections.Generic; [Serializable] [SqlUserDefinedAggregate( Format.UserDefined, //use clr serialization to serialize the intermediate result IsInvariantToNulls = true, //optimizer property IsInvariantToDuplicates = false, //optimizer property IsInvariantToOrder = false, //optimizer property MaxByteSize = -1) //maximum size in bytes of persisted value ] public struct GroupConcat : IBinarySerialize { private string _delimiter; private List<string> list; public void Init() { this._delimiter = ","; this.list = new List<string>(); } public void Accumulate([SqlFacet(MaxSize=-1)]SqlString value, SqlString delimiter) { if (value.IsNull) return; //string v = value.ToString().Replace(delimiter.ToString(), ""); string v = value.ToString(); this._delimiter = delimiter.ToString(); if (!this.list.Contains(v)) this.list.Add(v); } public void Merge(GroupConcat other) { foreach(string v in other.list) { if (!this.list.Contains(v)) this.list.Add(v); } } [return: SqlFacet(MaxSize = -1)] public SqlString Terminate() { if (this.list.Count == 0) return SqlString.Null; string output = string.Join(this._delimiter, this.list.ToArray()); return new SqlString(output); } public void Read(BinaryReader r) { this._delimiter = r.ReadString(); string output = r.ReadString(); if (!string.IsNullOrEmpty(output)) { string[] arg = output.Split(new string[] { this._delimiter }, StringSplitOptions.None); this.list = new List<string>(arg); } else { this.list = new List<string>(); } } public void Write(BinaryWriter w) { string output = string.Join(this._delimiter, this.list.ToArray()); w.Write(this._delimiter); w.Write(output); } }
Visual Studioで SQL CLR データベースプロジェクトを作ってSQL Serverに配置して、使うときは↓
select dbo.GroupConcat(name, ', ') note from employee
こういう感じでMySQLのGROUP_CONCATと同じく区切り文字を指定できます。
- 作者: 松本美穂,松本崇博
- 出版社/メーカー: ソシム
- 発売日: 2012/09/18
- メディア: 単行本
- クリック: 4回
- この商品を含むブログ (2件) を見る
PHPで郵便番号データを加工する
郵便局で公開されている郵便番号データって、色々とまずいところがありすぎてそのまま使うことはできないんですね。今頃になって知りました。
- zipcloud
http://zipcloud.ibsnet.co.jp/ - 郵便番号データは自分で加工しない
http://d.hatena.ne.jp/dayflower/20100929/1285744153
複数行にデータが分割されていたり、町域名に実際の住所ではないデータが混じってたり。ちゃんと郵便番号データを加工せずにそのまま使ってしまうと、こんなのとかこんなのが出てきて恥ずかしいことになる。
自分の目的は郵便番号から簡単な住所入力補助なので、最低限のデータ加工のみ行ってみました。
- 複数行に分割された町域名のマージ。
- 町域名に「以下に掲載がない場合」、または「の次に番地がくる場合」が含まれる場合は、町域名を消す。
- 町域名に「一円」が含まれ、実際の町域名が「一円」ではなさそうな場合、町域名を消す。
※市区町村名='北安曇郡松川村', 町域名='松川村一円' のように市区町村名と同じ内容が町域名に繰り返される場合は消す。
※市区町村名='犬上郡多賀町', 町域名='一円' のような場合は消さない。 - 町域名に「(」が含まれる場合、括弧以降を消す。
※大通西(1~19丁目) → 大通西
※みなとみらいクイーンズタワーA(6階) → みなとみらいクイーンズタワーA のように。
これ以降のことは、データを使うときにSQLなり何なりで処理する予定。
$path = "./KEN_ALL.CSV"; $records = load_postal_cd_csv($path); foreach($records as $i=>$row) { //消す if(contains($row[8], '合以下に掲載がない場') || contains($row[8], 'の次に番地がくる場合')) { //echo $row[8].'<br />'; $records[$i][5] = NULL; $records[$i][8] = NULL; } //存在する地名以外の「一円」を消す if(contains($row[8], '一円')) { $row[8] = preg_replace('/一円/', '', $row[8]); if(contains($row[7], $row[8])) { $records[$i][5] = NULL; $records[$i][8] = NULL; } } //開き括弧から後ろを消す $pos = mb_strpos($records[$i][8], '('); if($pos > 0) { $records[$i][8] = mb_substr($records[$i][8], 0, $pos); } //DBに登録するなり何なり。 echo $records[$i][2].' '.$row[6].$row[7].$records[$i][8].'<br />'; } //郵便番号CSVデータを読込む //町域名が分割されている場合はマージする function load_postal_cd_csv($path) { $records = array(); $merge = array(); $bracketed = FALSE; $fp = fopen($path, 'r'); $ret = TRUE; $row = 0; while (($data = fgetcsv($fp, 0, ",")) !== FALSE) { $chouiki = $data[8]; $row = NULL; $merged = FALSE; //括弧は出現していない if( ! $bracketed) { if( ! contains($chouiki, '(') ) { //括弧の無い通常の行 $row = $data; } else { if( contains($chouiki, ')') ) { //括弧の含まれる通常の行 $row = $data; } else { //閉じ括弧が無い $bracketed = TRUE; $merge = array($data); } } } else { if( contains($chouiki, ')') ) { //閉じ括弧あり(ここまでをマージ) $bracketed = FALSE; $merge[] = $data; $row = merge_rows($merge); $merge = array(); $merged = TRUE; } else { //閉じ括弧が無い //3行以上に分割された行 $merge[] = $data; } } if($row) $records[] = $row; //if($merged) { // echo $row[5].'<br />'; // echo $row[8].'<br />'; //} } return $records; } //行マージ function merge_rows($rows) { $prev_chouiki_kana = $rows[0][5]; $ret = $rows[0]; for($i=1; $i<count($rows); $i++) { $row = $rows[$i]; $ret[8] .= $row[8]; //町域(漢字)をマージ //カナは前行と同じものが繰り返し出現することがあるようなので重複は除く if($prev_chouiki_kana != $row[5]) $ret[5] .= $row[5]; //町域(カナ)をマージ } return $ret; } function contains($chouiki, $str) { $pos = mb_strpos($chouiki, $str); return !($pos === FALSE); }
PHP逆引きレシピ 第2版 (PROGRAMMER’S RECiPE)
- 作者: 鈴木憲治,山田直明,山本義之,浅野仁,櫻井雄大,安藤建一
- 出版社/メーカー: 翔泳社
- 発売日: 2013/10/22
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る