目次
| OS | Windows XP Home Edition SP2 |
| CPU | Athlon 64 Processor 3500+ (2.2GHz) |
| Memory | DDR-SDRAM 1GB |
| Graphics | ATI RADEON XPRESS 200 Series 1024x768 32bit |
| Sound | Realtek High Definition Audio |
| Network | Yahoo!BB 8M (Survey: Down=2.8Mbps, Up=509Kbps) |
| Develop Env. | Delphi 7 Professional |
| コンポーネント名 | 作者 | 用途 |
|---|---|---|
| TWaveFFT | ヒロユキ | 音声スペクトル分析 |
| TActionManager | Borland | メニュー管理 |
| TXPColorMap | Borland | XP風メニュースタイル |
| TSaveDialog | Borland | 未使用 |
| TPopupMenu | Borland | BGMオープン |
| TIdTcpClient | Indy Project | サーバとの通信用 |
| TTimer | Borland | プログレスバー更新 送受信状態監視 自動放送開始 メーター更新 カレントステータス更新 自動放送メイン |
| TOpenDialog | Borland | BGMオープン |
| TGogoTea | M.yanagisawa さん | mp3エンコード |
| TKThdComp | こける さん | mp3取り出し・データ送信 カレントステータス取得 |
| TIdEncoderMIME | Indy Project | パスワード符号化用 |
| TActionList | Borland | アクション管理 |
| TFindFile | M&I さん | 効果音検索 |
| TDDSD | Taku Hayase さん | 音声取り込み |
| TIdLogEvent | Indy Project | 送信データ量監視 |
| TMixer | Vivas さん | ミキサーのコントロール |
| TApplicationEvents | Borland | 例外捕捉 ホットキー処理 スレッド開始 |
| TIdHTTP | Indy Project | 番組リスト取得 |
| TImageList | Borland | タブ用アイコン |

| 名前 | 値の意味 | デフォルトまたは規定値 (太字:関数、斜体:パラメータ) |
備考 |
| Content-Type | 送るデータの種類 | audio/mpeg | |
| Authorization | Base64にエンコードしたパスワード | Basic Base64("source:パスワード") | パスワードは今のところ"ladio" |
| ice-name | ラジオ名 | 表示にのみ使われる | |
| ice-url | 関連URL | ||
| ice-genre | ジャンル(説明) | ||
| ice-bitrate | ビットレート(kbps単位の数値) | ||
| ice-description | ラジオ名 | ||
| ice-public | ? | 0 | |
| ice-audio-info | 再生情報 | ice-samplerate=サンプルレート(Hz);ice-bitrate=ビットレート(kbps);ice-channels=チャネル数 | これを間違うと再生できない |
| 見本(プレーンテキスト) |
| SOURCE /mountpoint ICE/1.0 Content-Type:audio/mpeg Authorization:Basic c291cmNlOmxhZGlv ice-name:YKK夜のラジオDX ice-url:http://www.plusradi.com/ ice-genre:とにかく喋ります。時々唄います。 ice-bitrate:128 ice-public:0 ice-description:YKK夜のラジオDX ice-audio-info:ice-samplerate=22050; ice-bitrate=128; ice-channels=1 |
procedure TForm1.StartBroadcast;
var
Header : TStringList;
Password : String;
begin
// エラーチェック
if マウントポイント = '' then
begin
raise Exception.Create('マウントポイントを入力してください');
end;
Header := TStringList.Create;
try
// クライアントの設定
IdTcpClient1.Host := サーバー;
IdTcpClient1.Port := ポート;
Password := IdEncoderMIME1.EncodeString('source:'+パスワード);
// ヘッダの設定
Header.NameValueSeparator := ':';
with Header do
begin
Add(Format('SOURCE %s ICE/1.0',[マウントポイント]));
Values['Content-Type'] := 'audio/mpeg';
Values['Authorization'] := 'Basic ' + Password;
Values['ice-name'] := ラジオ名;
Values['ice-url'] := 関連URL;
Values['ice-genre'] := ジャンル;
Values['ice-bitrate'] := ビットレート;
Values['ice-public'] := '0';
Values['ice-description'] := ラジオ名;
Values['ice-audio-info'] := Format(
'ice-samplerate=%d;ice-bitrate=%d;ice-channels=%d',[
サンプリングレート,
ビットレート,
チャネル数
]
);
end;
// 接続
IdTCPClient1.Connect();
// ヘッダ送信
IdTCPClient1.Write('');
IdTCPClient1.Write(Header.Text);
IdTCPClient1.WriteLn;
// レスポンスを待つ
IdTCPClient1.ReadLnWait;
finally
Header.Free;
end;
end;
DirectSoundCaptureEnumerate(lpDSEnumCallback(コールバック関数へのポインタ),nil);
function DSEnumProc(lpGUID:PGUID; lpszDesc,lpszDrvName:PChar;lpContext:Pointer):Boolean; stdcall;
var
DeviceName : String;
DeviceGUID : PGuid;
begin
DeviceName := lpszDesc;
if lpGUID = nil then
begin
DeviceName := 'プライマリデバイス';
DeviceGUID := nil;
end else
begin
// メモリを確保してGUIDを保存。ソフト終了時にFreeMemで解放すること
GetMem(DeviceGUID, sizeof(TGuid));
DeviceGUID^ := lpGuid^;
end;
// ここでGUID(へのポインタ)とデバイス名をセットにして保存。コンボボックスに保存する例は↓
//Form1.ComboBox22.Items.AddObject(DeviceName, TObject(DeviceGUID));
// 戻り値はtrue
Result := true;
end; 使用しているデバイスを変更するためには、TDDSDCaptureを少し改造する必要があります。//コンストラクタ
constructor TDDSDCapture.Create(OWner: TObject; Device:DSound.PGuid=nil);
var
ret : Cardinal;
begin
FOwner:=Owner;
FLength:=0;
FOnRecording:=Nil;
//DirectSoundCaptureオブジェクトの生成
ret := DirectSoundCaptureCreate8(Device, FDSCapture, Nil);
if ret <> DS_OK then begin
FInitialized:=False;
exit;
end;
//初期化はOK
FInitialized:=True;
end; 変更したTDDSDCaptureを使って、次のようにデバイスを変更します(例)。Capture.OnRecording := nil; Capture.Stop; Capture.Free; Capture := TDDSDCapture.Create(DDSD1, PGuid(Pointer to GUID); Capture.SetupCaptureBuffer(44100,16,Channels=2,NUM_SAMPLE*Channels*2); Capture.OnRecording := Captured; Capture.StartLoop;
procedure GetAndCheck();
var
Lines : TStringList;
Block : TStringList;
i,j : Integer;
InBlock : Boolean;
c : Integer;
Flag : Boolean;
begin
Lines := TStringList.Create;
Block := TStringList.Create;
try
try
Lines.Text := IdHttp1.Get('http://yp.ladio.livedoor.jp/stats/list.dat');
except
end;
// 初期化
Flag := false;
InBlock := false;
c := 0;
for i := 0 to Lines.Count-1 do
begin
if (Lines[i] = '') then continue;
if (Lines[i] = '') then
begin
if (not InBlock) then continue
else
begin
// ここでBlock.Values['キー名'] としてラジオ情報を取得できる
if StrtoInt(Block.Values['prt']) = ポート then
begin
if Block.Values['mnt'] = マウントポイント then
begin
// 載っていた
Flag := true;
break;
end;
end;
Inc(c);
InBlock := false;
continue;
end;
end;
if (not InBlock)and(Lines[i] <> '') then
begin
InBlock := true;
Block.Clear;
end;
if InBlock then Block.Add(Lines[i]);
end;
if not Flag then
begin
// 載っていなかった
end;
finally
Lines.Free;
Block.Free;
end;
end;
procedure TForm1.KThdComp1Execute(Sender: TObject);
const
MAX_SIZE = 100*1024*1024; // 100MB
var
Buffer : PChar;
Buffer2 : PByte;
Reader : TFileStream;
TrueRead : Integer;
ResetFlag : Boolean;
Size : Integer;
DontReset : Boolean;
begin
if Exclusive then exit;
Size := CopySize;
DontReset := false;
Exclusive := true;
GetMem(Buffer,Size);
GetMem(Buffer2,Size);
try
KThdComp1.Synchronize(Integer(Buffer),0);
//BlockCopy(Capture,StartOffset, Buffer, Size);
// フィルタと音量
FilterWave(
Pointer(Buffer),
Size div sizeof(T16bitSound),
SignalL,
SignalR,
StrtoInt(ComboBox2.Text) div 2
);
// リサンプラ
Size := Resampler(Pointer(Buffer), Size div sizeof(T16bitSound)) * sizeof(T16bitSound);
// バッファ書き込み
Gogotea1.WriteBuffer(Buffer, Size);
// ストリーム読み込み
Reader := TFileStream.Create(DestFile,fmOpenRead or fmShareDenyNone);
try
// 新規のデータを取り出す
Reader.Position := mp3pos;
TrueRead := Reader.Read(Buffer2^, Size);
IdTcpClient1.WriteBuffer(Buffer2^,TrueRead);
// 既定の容量を超したらリセット
ResetFlag := false;
if Reader.Size > MAX_SIZE then ResetFlag := true;
finally
mp3pos := Reader.Position;
Reader.Free;
end;
if (ResetFlag)and(not DontReset) then
begin
// エンコード中断
Gogotea1.WriteBuffer(nil,0);
Gogotea1.AbortEncode;
while Gogotea1.IsEncoding do sleep(10);
// キャッシュ削除
DeleteFile(DestFile);
mp3pos := 0;
// 再実行
Gogotea1.QuerySettings;
Gogotea1.Execute;
end;
finally
Exclusive := false;
FreeMem(Buffer);
FreeMem(Buffer2);
end;
end;