knzkwork-blog
knzkwork-blog
Kino's Note
5 posts
dlang / Linux / Gaming Twitter : @knzk_work
Don't wanna be here? Send us removal request.
knzkwork-blog · 7 years ago
Text
頂点シェーダーを使ってウィンドウ座標でポリゴンを描画
頂点シェーダーを使って普通のウィンドウ座標でポリゴンを描画する方法です。
頂点シェーダのコード
#version 330 uniform mat4 orthoMatrix; attribute vec2 position; void main ( void ) { gl_Position = orthoMatrix * vec4( position.x, -position.y, 0.0, 1.0 ); }
orthoMatrixが今回の肝で、この変数にCPU側から平行投影行列を渡します。 この平行投影行列は、左の大きさを0に、右の大きさをウィンドウ幅に、上の大きさを0に、下の大きさをウィンドウ高さ*-1にする必要があります。
つまり、ここの関数で以下の様に生成した並行投影行列を使う必要があります。
mat4.orthographic( 0f, size.width*1f, -size.height*1f, 0f, int.max*1f, int.min*1f );
これでウィンドウ座標でポリゴンを配置することが出来るようになります。
0 notes
knzkwork-blog · 7 years ago
Text
D言語製のFFmpegラッパをリリースした
FFmpegは破壊的変更が多すぎてバージョンが少し違うだけでエラーが出るで有名です。
そこで、FFmpegのラッパーライブラリをD言語で作ってみました。 エラー「そこで」: 順接接続詞の誤用
日本語力の低さはそこらへんの溝にでも捨て置いて、今日はそのライブラリ「MedIO」を紹介しようかと思います。
MedIOのコンセプト
このライブラリのコンセプトは「簡単にFFmpegを扱ってエンコードやデコードを扱えるようにすること」です。
プロジェクトのtest.dを見ていただけるとわかると思いますが、100行未満のコードで音声のある動画を出力しています。
普通にFFmpegライブラリを使えば100行でエンコード処理を収めるのは、ウンコードを覚悟して書かないと無理でしょう。 test.dの内容がウンコードならば話は別ですが。
名前の由来
Media + Input/Outputが由来です。安直ですね。
というわけで今回はMedIOの紹介でした。
MedIO: FFmpeg Wrapper Library for dlang
0 notes
knzkwork-blog · 7 years ago
Text
Ampacheのススメ
作業用BGMとかはYouTubeのプレイリストとかで保存しておくのもいいですが、少し機能が足りないなと思った人におすすめなのがAmpache。
Ampacheはウェブ上のiTunesみたいなもので、VPSを借りてnginx+phpfpm+mysqlの構成を作れば簡単にインストールできます。
ウェブ上という部分が肝で、ブラウザだけで音楽プレイヤーの代わりになるので、ほぼすべての端末で自分な好きな曲をすぐに聞ける点の素晴らしみが深いです。 つまり、借りたPCで作業するときも何かをインストールすることなく音楽を聞けるのです!
再生するときはストリーミング再生になるのでディスクを圧迫することもありません!
さあ今すぐVPS借りてAmpacheをインストールしよう。
Ampache: for the love of music.
Tumblr media
0 notes
knzkwork-blog · 7 years ago
Text
D言語でALSA (PCM再生)
WaveOutAPIの次はALSAで音を再生します。WaveOutAPIよりすこし難しかったです。
These codes play sounds using ALSA. Using ALSA is more difficult than WaveOutAPI.
// Written in the D programming language.//// You have to install libasound-dev.// Compile Command: dmd -of alsa_out alsa_out.dimport core.thread; import std.conv, std.math, std.random, std.string; pragma( lib, "asound" ); extern (C) nothrow @nogc { alias snd_pcm_uframes_t = ulong; alias snd_pcm_state_t = int; enum SND_PCM_STATE_RUNNING = 3; alias snd_pcm_stream_t = int; enum SND_PCM_STREAM_PLAYBACK = 0; enum SND_PCM_STREAM_CAPTURE = 1; alias snd_pcm_access_t = int; enum SND_PCM_ACCESS_RW_INTERLEAVED = 3; alias snd_pcm_format_t = int; version ( LittleEndian ) enum SND_PCM_FORMAT_S16 = 2; version ( BigEndian ) enum SND_PCM_FORMAT_S16 = 3; struct snd_pcm_hw_params_t {} int snd_pcm_hw_params_malloc ( snd_pcm_hw_params_t** ); int snd_pcm_hw_params_any ( snd_pcm_t*, snd_pcm_hw_params_t* ); int snd_pcm_hw_params_set_rate_resample ( snd_pcm_t*, snd_pcm_hw_params_t*, uint ); int snd_pcm_hw_params_set_access ( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_access_t ); int snd_pcm_hw_params_set_format ( snd_pcm_t*, snd_pcm_hw_params_t*, snd_pcm_format_t ); int snd_pcm_hw_params_set_channels ( snd_pcm_t*, snd_pcm_hw_params_t*, uint ); int snd_pcm_hw_params_set_rate_near ( snd_pcm_t*, snd_pcm_hw_params_t*, uint*, int* ); int snd_pcm_hw_params_set_buffer_time_near ( snd_pcm_t*, snd_pcm_hw_params_t*, uint*, int* ); int snd_pcm_hw_params_get_buffer_size ( snd_pcm_hw_params_t*, snd_pcm_uframes_t* ); int snd_pcm_hw_params_set_period_time_near ( snd_pcm_t*, snd_pcm_hw_params_t*, uint*, int* ); int snd_pcm_hw_params_get_period_size ( snd_pcm_hw_params_t*, snd_pcm_uframes_t*, int* ); int snd_pcm_hw_params ( snd_pcm_t*, snd_pcm_hw_params_t* ); int snd_pcm_hw_params_free ( snd_pcm_hw_params_t* ); struct snd_pcm_sw_params_t {} int snd_pcm_sw_params_malloc ( snd_pcm_sw_params_t** ); int snd_pcm_sw_params_current ( snd_pcm_t*, snd_pcm_sw_params_t* ); int snd_pcm_sw_params_set_start_threshold ( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t ); int snd_pcm_sw_params_set_avail_min ( snd_pcm_t*, snd_pcm_sw_params_t*, snd_pcm_uframes_t ); int snd_pcm_sw_params ( snd_pcm_t*, snd_pcm_sw_params_t* ); int snd_pcm_sw_params_free ( snd_pcm_sw_params_t* ); struct snd_pcm_t {} snd_pcm_state_t snd_pcm_state ( snd_pcm_t* ); int snd_pcm_open ( snd_pcm_t**, const char*, snd_pcm_stream_t, int ); int snd_pcm_writei ( snd_pcm_t*, const void*, snd_pcm_uframes_t ); int snd_pcm_start ( snd_pcm_t* ); int snd_pcm_avail_update ( snd_pcm_t* ); int snd_pcm_drop ( snd_pcm_t* ); alias snd_async_callback_t = void function ( snd_async_handler_t* ); struct snd_async_handler_t {} int snd_async_add_pcm_handler ( snd_async_handler_t**, snd_pcm_t*, snd_async_callback_t, void* ); snd_pcm_t* snd_async_handler_get_pcm ( snd_async_handler_t* ); void* snd_async_handler_get_callback_private ( snd_async_handler_t* ); const(char*) snd_strerror ( int ); } template enforce ( alias func ) { auto enforce ( string file = __FILE__, size_t line = __LINE__, Args... ) ( Args args ) { auto result = func( args ); if ( result < 0 ) throw new Exception( snd_strerror( result ).to!string, file, line ); return result; } } short[] createWave ( ulong samples, uint chnls ) { short[] result; result.length = samples*chnls; auto ptr = result.ptr; int j; short s; auto rnd = new Random( 150 ); for ( ulong i = 0; i < samples; ) { s = ( uniform( short.min, short.max, rnd ) ).to!short; for ( j = 0; j < chnls; j++ ) ptr[i++] = s; } return result; } struct AsyncPrivateData { snd_pcm_uframes_t periodSize; snd_pcm_uframes_t index; snd_pcm_uframes_t sampleCount; short[] samples; } static extern(C) void asyncCallback ( snd_async_handler_t* handle ) nothrow @nogc { snd_pcm_t* device = snd_async_handler_get_pcm( handle ); AsyncPrivateData* data = cast(AsyncPrivateData*)snd_async_handler_get_callback_private( handle ); auto periodSize = data.periodSize, sampleCount = data.sampleCount; while ( snd_pcm_avail_update( device ) >= data.periodSize && data.index<sampleCount ) { auto size = data.index+periodSize >= sampleCount? sampleCount-data.index: periodSize; data.index += size; snd_pcm_writei( device, &(data.samples.ptr[data.index]), size ); } if ( data.index >= data.sampleCount ) snd_pcm_drop( device ); } void main ( string[] args ) { uint samplingRate = 48000, channels = 2, duration = 5, bufferTime = 500000, periodTime = 100000; snd_pcm_t* device; enforce!snd_pcm_open( &device, "hw:0,0".toStringz, SND_PCM_STREAM_PLAYBACK, 0 ); snd_pcm_uframes_t bufferSize, periodSize; { // set hardware parameters snd_pcm_hw_params_t* hwp; enforce!snd_pcm_hw_params_malloc( &hwp ); enforce!snd_pcm_hw_params_any( device, hwp ); enforce!snd_pcm_hw_params_set_rate_resample( device, hwp, 1 ); enforce!snd_pcm_hw_params_set_access( device, hwp, SND_PCM_ACCESS_RW_INTERLEAVED ); enforce!snd_pcm_hw_params_set_format( device, hwp, SND_PCM_FORMAT_S16 ); enforce!snd_pcm_hw_params_set_channels( device, hwp, channels ); enforce!snd_pcm_hw_params_set_rate_near( device, hwp, &samplingRate, null ); enforce!snd_pcm_hw_params_set_buffer_time_near( device, hwp, &bufferTime, null ); enforce!snd_pcm_hw_params_get_buffer_size( hwp, &bufferSize ); enforce!snd_pcm_hw_params_set_period_time_near( device, hwp, &periodTime, null ); enforce!snd_pcm_hw_params_get_period_size( hwp, &periodSize, null ); enforce!snd_pcm_hw_params( device, hwp ); } { // set software parameters snd_pcm_sw_params_t* swp; enforce!snd_pcm_sw_params_malloc( &swp ); enforce!snd_pcm_sw_params_current( device, swp ); enforce!snd_pcm_sw_params_set_start_threshold( device, swp, bufferSize ); enforce!snd_pcm_sw_params_set_avail_min( device, swp, periodSize ); enforce!snd_pcm_sw_params( device, swp ); } { // play AsyncPrivateData data; data.sampleCount = duration*samplingRate; data.samples = createWave( data.sampleCount, channels ); data.index = 0; data.periodSize = periodSize; snd_async_handler_t* handler; enforce!snd_async_add_pcm_handler( &handler, device, &asyncCallback, &data ); data.index += periodSize; enforce!snd_pcm_writei( device, data.samples.ptr, periodSize ); enforce!snd_pcm_start( device ); data.index += periodSize; enforce!snd_pcm_writei( device, data.samples.ptr, periodSize ); while ( snd_pcm_state( device ) == SND_PCM_STATE_RUNNING ) Thread.sleep( dur!"msecs"(1) ); } }
すっごい長いですが、単純に再生したいだけならばもう少し短くできます。今回は並列再生をさせたかったのでここまで長くなってしまいました。
It looks too long, but you can shrink codes if you just wanna play without async.
0 notes
knzkwork-blog · 7 years ago
Text
D言語でWaveOutAPI (PCM再生)
今作っているライブラリで、WaveOutAPIをいじる必要があったのでメモっておきます。
I posted how to use WaveOutAPI because I had to use it.
// Written in the D programming language. // Compile Command: dmd -of waveout main.d winmm.lib import core.sys.windows.windows; import std.conv, std.math, std.stdio; alias PCMFormat = short; enum BitsPerSample = PCMFormat.sizeof*8; enum Channels = 1, SamplingRate = 44100, Duration = 5; enum WaveHz = 3000; void main () { WAVEFORMATEX wf; wf.wFormatTag = WAVE_FORMAT_PCM; wf.nSamplesPerSec = SamplingRate.to!WORD; wf.nChannels = Channels.to!WORD; wf.wBitsPerSample = BitsPerSample; wf.nBlockAlign = (wf.nChannels*wf.wBitsPerSample / 8).to!WORD; wf.nAvgBytesPerSec = wf.nSamplesPerSec*wf.nBlockAlign; wf.cbSize = 0; HWAVEOUT device; "waveOutOpen: ".write; waveOutOpen( &device, WAVE_MAPPER, &wf, 0, 0, CALLBACK_NULL ).writeln; uint volume = 0; "waveOutGetVolume: ".write; waveOutGetVolume( device, &volume ).writeln; "=> left volume: %d, right volue: %d, (%d)".writefln( volume&0xff00>>8, volume&0xff, volume ); PCMFormat[] pcm; pcm.length = SamplingRate*Channels*Duration; for ( auto i = 0; i < pcm.length; ) { auto p = ( sin( WaveHz*PI*2*i/pcm.length ) * PCMFormat.max ).to!PCMFormat; for ( auto j = 0; j < Channels; j++ ) pcm.ptr[i++] = p; } WAVEHDR wh; wh.lpData = cast(LPSTR) pcm.ptr; wh.dwBufferLength = pcm.length*PCMFormat.sizeof; wh.dwFlags = 0; wh.dwLoops = 1; wh.dwBytesRecorded = 0; wh.dwUser = 0; wh.lpNext = null; wh.reserved = 0; "waveOutPrepareHeader: ".write; waveOutPrepareHeader( device, &wh, WAVEHDR.sizeof ).writeln; "waveOutWrite: ".write; waveOutWrite( device, &wh, WAVEHDR.sizeof ).writeln; import core.thread; Thread.sleep( dur!"seconds"( 5 ) ); "All codes have been executed. Press enter key...".writeln; readln(); "waveOutClose: ".write; waveOutClose( device ).writeln; }
重要なポイントとして、WAVEHDR構造体は再生が終わるまでとっておかないと再生が途中で終わったり、再生されなかったりします。(ここにハマった)
You must be careful that don't release the WAVEHDR variable before finish the playing.
0 notes