Mengawali tahun baru 2010, saya ingin bercerita tentang eksperimen yang dikerjakan selama liburan tahun baru yang lalu.

GLUT (OpenGL Utility Toolkit) merupakan library lintas platform yang membungkus fungsi-fungsi windowing dan interaksi untuk aplikasi yang berbasis openGL. Jika tidak menggunakan GLUT maka di Win32 kita harus menggunakan MFC atau memanfaatkan Win32 API (mendaftarkan window class, WndProc, membuat OpenGL Context, dll). Karena pada Visual C++ 2008 express tidak ada MFC dan ATL maka pilihan tinggal pada WIn32 API, dan tersedianya GLUT akan memudahkan pengembangan aplikasi. Esensi glut sebetulnya adalah membuat abstraksi pembuatan window dan mekanisme interaksi pada beberapa platform tanpa harus banyak mengubah kode sehingga akses untuk hal-hal yang spesifik platform tidak bisa diakses secara langsung. Sampai ketika dihadapkan pada kasus yang mengharuskan menghubungkan antara MS Speech SDK dengan Visualisasi animasi yang berbasis OpenGL (menggunakan GLUT), pendek kata : memvisualisasikan animasi wajah dengan kata yang diucapkan oleh engine TTS (the good ol' microsoft Sam LoL). Agar kita mengetahui gerak bibir (viseme) maka kita harus mendaftarkan window handle (HWND) ke komponen TTS (SpVoice) sehingga komponen tersebut dapat mengirimkan Window Message tertentu yang berisi informasi tentang viseme yang sedang dan akan diputar. duh, banyak sekali basa-basinya. mari kita mulai terjun ke kode.

Menggunakan Komponen TTS dari MS Speech SDK


#include <windows.h>
#include <sapi.h>

//...

#define WM_TTSAPPCUSTOMEVENT WM_APP // Window message used for systhesis events

//...

//tts engine
ISpVoice *spVoice;

//required variables
HWND hWnd;
WNDPROC currentWndProc;

int main(int argc, char* argv[])
{
CoInitialize( NULL );
//create ttsengine
if ( SUCCEEDED( CoCreateInstance( CLSID_SpVoice , NULL, CLSCTX_ALL, IID_ISpVoice, (void**)&spVoice ) ) ){
//tanda -*- akan digunakan sebagai penanda penyisipan kode berikutnya

//-*-


//talk now
spVoice->Speak(L"Hello World!", SVSFDefault);

spVoice->Release();
spVoice = NULL;
}

CoUninitialize();

return EXIT_SUCCESS;
}

Menerima event tiap viseme diucapkan

agar dapat menerima setiap viseme yang diucapkan, maka kita mendaftarkan window handle yang akan menerima message dan message apa yang akan digunakan.

		//-*-
//register for notification
spVoice->SetInterest( SPFEI(SPEI_VISEME), SPFEI(SPEI_VISEME));
spVoice->SetNotifyWindowMessage( hWnd, WM_TTSAPPCUSTOMEVENT, 0, 0 );
Persoalannya berikutnya adalah: "jika kita menggunakan glut, bagaimana mendapatkan handle window dan bagaimana menangani message yang dikirim dari komponen Voice tersebut?"
agar dapat menjawab pertanyaan tersebut maka kita perlu melakukan beberapa trik berikut:
		//hook glut wndproc
hWnd = FindWindow(L"GLUT", NULL);
currentWndProc = (WNDPROC)GetWindowLong(hWnd, GWL_WNDPROC);
SetWindowLong(hWnd, GWL_WNDPROC, (long)winProc);
//-*-
Ya, kita perlu membuat fungsi WindowProc baru yang digunakan pada window buatan GLUT, memroses pesan yang kita perlukan lalu mengembalikan kembali ke prosedur WndProc aslinya (seperti virus jaman DOS yang meng-intercept interrupt vector, hahaha). Untuk itu, diperlukan fungsi winProc (sesuai definisi di atas) sbb:
//WindowProc Hook to handle TTS Event
LRESULT CALLBACK winProc(HWND hwnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
switch (Msg)
{
case WM_TTSAPPCUSTOMEVENT:
SPEVENT eventItem;
memset( &eventItem, 0,sizeof(SPEVENT));
while( spVoice->GetEvents(1, &eventItem, NULL ) == S_OK )
{
switch(eventItem.eEventId )
{
case SPEI_VISEME :
cur_frame = VisemeToFrame[LOWORD(eventItem.lParam)];//current viseme id
next_frame = VisemeToFrame[LOWORD(eventItem.wParam)];//next viseme id
anim_duration = HIWORD(eventItem.wParam);//this viseme duration in ms
cur_time = GetTickCount();
last_time = cur_time;
break;

default:
break;
}

//SpClearEvent( &eventItem );
}
break;

default:
return currentWndProc(hwnd, Msg, wParam, lParam);//pass the message to the original handler
}
return 0;
}
hope this helps!
Share this post: | | | |

Sebetulnya UTS hari ini (jam 9 nanti) tentang intelejensia kolektif yang bahannya tentang EA (evolutionary algorithm) dan ACO (ant colony optimization), tapi yang dibaca sebelum tidur malah buku Practical Software Maintenance-nya Tom Pigoski. Kebetulan memang untuk kuliah pengujian perangkat lunak kebagian bab tentang testing pada saat maintenance. Baru baca bab-bab awal. Persepsi awal tentang isinya lumayan menarik sambil merefleksikan masa-masa yang pernah dialami (sebetulnya istilah pengalaman lebih singkat tapi punya makna konotasi yang bisa baik bisa juga jelek :D).

Singkat kata, dari bacaan awal bisa diceritakan bahwa perawatan (padanan untuk maintenance) seringkali memiliki banyak interpretasi. Perawatan bisa jadi merupakan pengeluaran yang kecil dibanding biaya pengembangan atau justru menjadi pengeluaran utama dibanding biaya pengembangan. Interpretasi pertama dicirikan dengan adanya alokasi sekitar 10% untuk 'support & maintenance', sedangkan interpretasi kedua mengalokasikan 80% untuk hal tersebut. Pertanyaan pertama yang muncul adalah "Yang mana yang lebih baik? untuk developer, maintainer, dan customer" (pengguna dibedakan dengan customer dan dikesampingkan dulu karena berdasarkan buku tsb, tersangka utama penyedot biaya perawatan adalah pengguna).

Pihak yang melakukan perawatan pun bisa jadi bukan pengembang perangkat lunak awal melainkan pihak lain yang mengkhususkan diri di bidang perawatan perangkat lunak (itu cerita di bukunya dengan situasi di US, kalau di Indonesia ada tidak yah (organisasi spesialis perawatan)?).

Sebelum mencoba menjawab pertanyaan di atas, cerita lain tentang isi buku tsb adalah bahwa aktivitas yang dilakukan dalam proses perawatan bisa digolongkan menjadi 3 kelompok, yaitu:

  • corrective
  • adaptive
  • perfective/improvement

Kunci dari keberhasilan proses perawatan (lagi-lagi berdasarkan buku tsb.) adalah mengklasifikasikan hal-hal yang perlu berubah ke dalam kelompok tersebut. Pengklasifikasian di atas disusun berdasarkan prioritas dan resikonya. Kisaran proporsi ketiga kelompok tersebut berturut-turut 20%, 25%, dan 55%. intinya, kebanyakan dari perawatan adalah improvement. Celakanya permintaan atas improvement ini nggak melihat struktur perangkat lunak ada. Jadi ingat pernah ada yang minta ganti grid (standar VCL Delphi) biar tampak lebih menarik (Dibandinginnya dengan DataGrid defaultnya Flex). Ibaratnya, lagi nyetir mobil kecepatan tinggi tiba-tiba punggung itu gatal!.

IMHO, situasinya akan lebih enak kalau deskripsi sistem yang mau dibikin itu bisa selesai di 10% (lebih enak lagi kalau verifikasi kesesuaian dengan spesifikasinya bisa dilakukan otomatis menggunakan metode formal) waktu total pengembangan sistem sehingga 90 persen sisanya adalah proses maintenance & testing untuk menyesuaikan dengan kebutuhan yang diyakini selalu berubah. Aspek adaptif dan perfektif berhubungan dengan antarmuka dengan sistem lain (infrastruktur perangkat keras, API, sistem operasi, target deployment platform), dan manusia (user interaction).

Saya sendiri sebetulnya lebih tertarik ke interaksi. Bayangan saya adalah user interface yang dinamis (bukan sekedar style/theme yang hanya mencakup aspek estetis, tetapi juga struktur hierarki, tata letak, dan pemilihan komponen interaksi) yang menyesuaikan dengan target deployment platform (desktop, web, mobile) dan selera pengguna. Untuk itu diperlukan tool untuk membantu perancang interaksi (paradigma Microsoft) atau menjadi fasilitas yang terintegrasi dengan sistem yang digunakan oleh pengguna (end-user development). Satu hal yang pasti dengan adanya sistem antarmuka yang dinamis dan universal ini lahir kebutuhan baru yaitu pembuatan manual penggunaan yang otomatis juga.

Kalau diinventarisasi, untuk menyelesaikan persoalan di atas (pembangkitan antarmuka dan manual ~ user interface and instruction manual generation) perlu beberapa hal berikut:

  • pemodelan domain arsitektur informasi, interaksi, dan kapabilitas platform (domain spesific modeling, MDA) termasuk model pembangkitan teks narasi untuk menceritakan skenario interaksi(natural language processing) menjadi bahasa spesifik (domain spesific language).
  • teknik kompilasi, khususnya untuk proses generation dari domain spesific language ke kode target platform
  • pengetahuan tentang interaksi (teori aktivitas dan teori kognitif) yang menjadi batasan pada proses pencarian solusi
  • Teknik optimasi kombinatorial untuk menghasilkan solusi berupa konfigurasi yang diharapkan
Tampak terlalu besar cakupannya untuk dijadikan tesis (mungkin harusnya jadi program riset kk/unggulan?) dengan sisa waktu kurang dari satu semester. Mungkin bisa dibatasi lagi supaya lebih layak mengingat masih ada konsep-konsep yang sifatnya vague.
Share this post: | | | |

baru saja membuat tulisan di blog yang lain mengenai problem solving berjudul "berburu wanita"

all geeks invited! ;)
Share this post: | | | |

Baru tau kalo MS punya implementasi MPI (MSMPI) setelah baca tulisan di sini jadinya penasaran. langsung deh googling dan ternyata Pak Risman sempat menulis di sini. setelah mengunduh HPC SDK, hal pertama yang dicoba adalah menjalankan executable yang dibuat menggunakan library dari MPICH2. hasilnya? gagal

Setelah dibaca lagi dengan lebih teliti, ternyata OS yang sedang digunakan tidak didukung (XP Home Edition). OS yang didukung antara lain (dari situs download)

Windows XP Professional 32-bit
Windows XP Professional x64 edition
Windows Server 2003 32-bit
Windows Server 2003 x64 edition
Windows Vista 32-bit
Windows Vista x64
Windows Server 2008 32-bit
Windows Server 2008 x64 edition

penyebab detilnya adalah setelah memanggil 

mpiexec -n 3 d:\code\MPI\graph.exe

menghasilkan pesan kesalahan berikut 

The procedure entry point GetProcessIdOfThread could not be located in the dynamic link library KERNEL32.dll.

 setelah di intip, ternyata memang prosedur tersebut tidak ada (beda edisi (home sama pro) kok beda kernelnya yah?).

 satu hal lagi yang berbeda adalah local smpd manager pada MS-MPI tidak berjalan sebagai Windows Service seperti pada MPICH2.  sisanya belum ketahuan karena belum berhasil dicoba (sembari mencari komputer korban yang pakai XP Pro, WS2003 atau Vista, hehehe).

NB:Bagi yang tidak menyimak, judul tulisan ini bukan parallel computing tetapi parallel programming. ;)

Share this post: | | | |

 Hehe..setelah beberapa waktu lalu belajar Excel VBA, hari ini baru tahu caranya membuat add-in di Excel yang ternyata mudah. Tadinya juga nggak mudeng sama manfaat add-in, setelah tau bahwa dengan add-in ini bisa memanggil fungsi custom di cell (pakai prefix =) jadi asyik sendiri. :D

cara membuat fungsi baru sebagai add-in (file .xla) :

  1. buka Tools > Macro > Visual Basic Editor
  2. tambahkan module baru : Insert > Module
  3. buat fungsi yang ingin digunakan dengan modifier Public
  4. untuk mencoba fungsi yang baru dibuat, lihat di worksheet dan panggil (menggunakan =)
  5. untuk membaptis menjadi Excel Add-in, simpan sebagai (Save As) Excel Add-in (.xla)

berikut ini salah satu contoh fungsi yang menerima masukan Range 1 dimensi (fungsi untuk menghitung indeks keragaman)

Public Function IndexOfDiversity(R As Range)
    N = Application.WorksheetFunction.Count(R)
    Sum = 0#
    For i = 1 To N
        Sum = Sum + (R(i) * R(i))
    Next
    IndexOfDiversity = 1 - Sum
End Function 

Share this post: | | | |

Sekitar bulan maret 2008 saya dapet job untuk membuat gambar pada report di MS Access menggunakan VBA. Believe it or not, ketika saya menerima pekerjaan ini saya sama sekali belum pernah menggunakan VBA di Access. Walaupun waktu SMA sempat utak-atik Macro di MS Word untuk membuat worm. (i repeat, it's a worm.. not a virus) dan bermain-main dengan QBASIC dan QB 4.5 untuk membuat game (T_T i miss the good ol' times)...

Back to topic. Persoalannya adalah objek yang mau digambar itu adalah hasil perhitungan dari tabel lain dan report tidak bisa langsung dimanipulasi dari kode form. Jadi, setelah membaca beberapa ebook dan memprint kode existing projectnya ke kertas.. baru deh dapet ide untuk membuat gambar di report. triknya cukup trivial yaitu membuat tabel baru untuk menampung sementara objek yang ingin digambar (kalo di buku teks grafika jadul istilahnya display list). Setelah seluruh objek 'digambar' (memanggil fungsi perantara untuk menggambar), baru Report yang diinginkan ditampilkan. Di dalam report tersebut disisipkan lagi kode VBA yang akan melakukan actual drawing ke report.

prosedur di bawah ini adalah prosedur perantara yang saya maksud.

Public Sub DrawBOX(X1 As Integer, Y1 As Integer, X2 As Integer, Y2 As Integer)
    rs.Open "INSERT INTO t_box (x1, y1, x2, y2 ) VALUES( " & X1 & "," & Y1 & ", " & X2 & " , " & Y2 &  ")", CurrentProject.AccessConnection, adOpenDynamic, adLockReadOnly
End Sub

 setelah semua pemanggilan fungsi di atas selesai, langkah selanjutnya adalah menampilkan report yang bersangkutan

DoCmd.OpenReport strReportToAction, acViewPreview

Nah, pada report yang bersesuaian disisipkan kode yang memanggil fungsi-fungsi untuk menggambar di report tersebut pada event handler Page ;) misalnya seperti berikut

Private Sub Report_Page()

Dim rsd As ADODB.Recordset
    Set rsd = New ADODB.Recordset
    rsd.Open "SELECT * FROM t_box", CurrentProject.AccessConnection, adOpenDynamic, adLockReadOnly

    rsd.MoveFirst
    Do Until rsd.EOF
        Me.Line (ws * rsd(0), h_offset + ws * rsd(1))-(ws * rsd(2), h_offset + ws * rsd(3)), RGB(255, 0, 0), B
        rsd.MoveNext
    Loop
    rsd.Close

End Sub 

 

Share this post: | | | |

Aplikasi image browser yang ditulis sebelumnya awalnya mengandalkan loading image mentah-mentah (full size) yang bukan hanya memperlambat waktu loading, tetapi juga memakan banyak memori. bayangkan saja hanya untuk menampilkan sekitar 37 image, menghabiskan ~180MB! hasilnya? tentu saja overall system slowdown. Setelah baca di sini baru tahu kalau membuat thumbnail di WPF itu sangat mudah karena sudah langsung dibungkus di dalam kelas BitmapImage.

BitmapImage getThumb(string filename, int pixelSize)
        {
            
            BitmapImage bi = new BitmapImage();
            bi.BeginInit();
            bi.DecodePixelWidth = pixelSize;
            bi.CacheOption = BitmapCacheOption.OnLoad;
            bi.UriSource = new Uri(filename);
            bi.EndInit();
            return bi;
        }

dengan kode di atas, kita bisa langsung menambahkan jadi

ImageBrush ib = new ImageBrush(getThumb(filename, 128));
ib.Stretch = Stretch.Uniform;
Material material = new DiffuseMaterial(ib);

berhubung penggunaannya untuk aplikasi 3D yang memanfaatkan Graphics Hardware, jadinya ukuran thumbnail menggunakan rule-of-thumb power of 2 (nggak tau juga sih apa ini juga berlaku di WPF). Setelah dipakai, pemakaian memori turun ke angka 32 MB. lumayan lah..

Share this post: | | | |
Posted Monday, January 5, 2009 7:21 AM by pebbie | with no comments
Filed under:

scr001 Selalu ada yang pertama untuk banyak hal, termasuk kegagalan. Tulisan ini termasuk yang pertama dari saya di sini. Gambar di samping adalah gambar aplikasi wpf saya yang pertama yang (tadinya) diniatkan untuk dikutkan ke kompetisi wpf champion. tapi ternyata nggak berhasil selesai, masih banyak fitur yang ingin dimasukkan tapi belum berhasil diimplementasi.

Maksud hati ingin membuat image browser dalam lingkungan virtual 3D, tapi yang berhasil selesai baru menampilkan thumbnail. :D

wishlistnya :

  • loading image asynchronous (entah mengapa saya jadi nggak suka sama managed object.. such a bureaucratic world eh? hehehe) dan lebih cepat
  • menampilkan detil image dan animasinya
  • animasi transisi pergantian direktori
  • baloon hint untuk directory cube
  • billboarding
  • transformasi otomatis current view supaya jadi suggestive UI.

subjective conclusion :

  • dokumentasi msdn masih tetep nggak semudah javadoc, phpmanual atau help milik delphi 7 (:P)
  • Canvas, Viewport3D nggak bisa nerima event Mouse kalau nggak ada child object. masih nggak ngerti kenapa, padahal yang di-attach event handler kan si objek Canvas/Viewport3D bukan anak-anaknya..
  • code-only error-first prototyping nggak cocok bwt wpf kayaknya..
  • intellisense tidak selamanya cerdas, nggak jarang fitur ini malah mengganggu jalannya 'tarian jari'
Share this post: | | | |