• Tidak ada hasil yang ditemukan

3. PERANCANGAN SISTEM

N/A
N/A
Protected

Academic year: 2022

Membagikan "3. PERANCANGAN SISTEM"

Copied!
30
0
0

Teks penuh

(1)

Pada bab ini akan dijelaskan tentang perancangan software yang meliputi diagram blok secara keseluruhan dari mekanisme client dan

3.1. Perancangan

Sistem yang dibuat akan menggunakan skor dan daftar lagu MIDI yang ada.

menggunakan jaringan internet.

Kinect digunakan untuk mendeteksi pemain sistem:

3.1.1. Desain Server

Dalam sistem yang dibuat server dan sebagai file

MIDI yang disimpan di

3.1.1.1 Desain Database

Dalam sistem yang dibuat,

menyimpan 3 hal utama, yaitu data mengenai adalah gambar relationship

3. PERANCANGAN SISTEM

Pada bab ini akan dijelaskan tentang perancangan dan impl yang meliputi diagram blok secara keseluruhan dari

dan server.

Perancangan Sistem

Sistem yang dibuat akan menggunakan server sebagai penyimpan data skor dan daftar lagu MIDI yang ada. Client akan terhubung dengan

menggunakan jaringan internet. Client haruslah terhubung dengan

digunakan untuk mendeteksi pemain. Berikut gambar dari arsitektur

Gambar 3.1 Arsitektur Sistem

Server

Dalam sistem yang dibuat server hanya berfungsi sebagai file server (HTTP server) untuk tempat men-download disimpan di server.

abase

Dalam sistem yang dibuat, database yang dibuat berfungsi untuk menyimpan 3 hal utama, yaitu data mengenai player, file MIDI, dan

relationship dari 3 buah tabel yang ada.

dan implementasi yang meliputi diagram blok secara keseluruhan dari program, dan

sebagai penyimpan data akan terhubung dengan server haruslah terhubung dengan Kinect, karena . Berikut gambar dari arsitektur

hanya berfungsi sebagai database download file-file

yang dibuat berfungsi untuk MIDI, dan skor. Berikut

(2)

Dari Gambar 3.2. dapat dilihat kalau hubungan tabel Player dan Score adalah One-to-Many, karena satu pemain bisa memiliki banyak skor, sedangkan satu skor hanya mencatat skor 1 pemain saja. Hubungan tabel MIDI dan tabel skor juga sama, yaitu One-to-Many, karena satu MIDI bisa dimainkan oleh banyak pemain, maka satu file MIDI bisa memiliki banyak skor, sedangkan satu skor hanya mencatat skor satu lagu/MIDI.

Berikut adalah struktur dari tabel Player, MIDI dan Score.

Tabel 3.1 Struktur Tabel Player

Field Tipe Deskripsi

ID_Player Int (Primary Key) (Auto Increment) Nama_Pemain VarChar (Unique) Nick Name pemain Password VarChar Password untuk login

Tanggal_Join TimeStamp Mencatat tanggal registrasi pemain

Tabel 3.2 Struktur Tabel MIDI

Field Tipe Deskripsi

ID_MIDI Int (Primary Key) (Auto Increment) Nama_MIDI VarChar (Unique) Judul lagu MIDI Tanggal_MIDI TimeStamp Mencatat tanggal registrasi MIDI Link_MIDI VarChar (Unique) Mencatat link MIDI

Level Int Mencatat level MIDI

Tabel 3.3 Struktur Tabel Score

Field Tipe Deskripsi

ID_Score Int (Primary Key) (Auto Increment)

ID_Player Int (Foreign key) Menunjukan ID_Player pemilik score ID_MIDI Int (Foreign key) Menunjukan ID_MIDI yang dimainkan

Score Int Nilai score

Tanggal_Score TimeStamp Mencatat waktu Score di-submit ke server

3.1.1.2 Desain HTTP Server

HTTP server berfungsi untuk media transfer data file MIDI dan melayani download request dari client. Link-link MIDI yang tersimpan pada tabel MIDI,

(3)

3.1.2 Desain Client

Bagian ini akan menjelaskan desain client yang akan dibuat. Melingkupi desain tampilan, database yang akan digunakan, dan fitur yang dibuat.

3.1.2.1 Alur Halaman

Di dalam client yang dibuat, terdapat beberapa page tampilan, antara lain adalah main page, option page, song select page, dan game page. Berikut adalah alur halaman tampilan client.

Gambar 3.3 Alur Halaman Tampilan

Pertama-tama pemain haruslah terlebih dahulu login atau mendaftar, baru kemudian akan diarahkan ke Main page. Di dalam Main Page akan terdapat 2 pilihan, yaitu untuk menuju ke Option Page, atau masuk ke Select Song Page.

Pada Option Page terdapat pilihan seperti volume permainan, dan update file MIDI. Sedangkan pada Select Song Page terdapat list file MIDI yang ada di Client. Pemain akan memilih salah satu file dari list tersebut untuk memainkannya, kemudian pemain akan diarahkan ke Game Page. Pada Game Page, pemain akan bermain dengan menggunakan file MIDI yang telah dipilih.

(4)

3.1.2.2 Komunikasi Client Dengan Database Server

Untuk komunikasi client dengan Database Server mengunakan API ODBC (Open Database Connectivity). ODBC berfungsi untuk menghubungkan client dengan database yang ada di server. Pada sistem yang dibuat, client menggunakan ODBC 3.51.

Komunikasi antara server dan client digunakan untuk proses login dan registration, mengambil data skor yang ada, mengambil list file MIDI yang ada di server, dan untuk menambahkan skor hasil permainan ke server.

Berikut adalah protokol-protokol yang digunakan untuk proses membuka koneksi, login¸ registrasi, submit skor, dan update.

Gambar 3.4 Protokol Membuat Koneksi Database.

Protokol untuk membuka koneksi database ini digunakan supaya client bisa mengakses database server. Proses ini harus dilakukan terlebih dahulu sebelum client bisa melakukan proses-proses seperti login, registrasi, update, dan submit skor.

Pertama-tama client akan meminta koneksi kepada database server, kemudian server akan membuat koneksi dengan client. Permintaan koneksi dari client bisa saja ditolak apabila client tidak memiliki izin untuk mengakses database server.

(5)

Gambar 3.5 Protokol Login.

Pada proses login, client terlebih dahulu membentuk koneksi dengan database server. Setelah koneksi terbentuk, client akan mengirimkan username dan password. Apabila pada tabel player terdapat username yang dikirimkan menggunakan password yang dikirimkan, maka server akan mengirimkan balasan ID_PLAYER dari pemain tersebut ke client. ID_PLAYER ini akan disimpan, dan digunakan apabila pemain tersebut melakukan proses submit skor.

Gambar 3.6 Protokol Registrasi.

(6)

Pada proses registrasi, client terlebih dahulu membentuk koneksi dengan database server. Setelah koneksi terbentuk, client akan mengirimkan username dan password yang akan didaftarkan. Karena data Nama_Pemain pada tabel Player bersifat unique atau tidak boleh ada yang sama, maka apabila username yang akan didaftarkan sudah terdaftar pada tabel Player, server tidak akan mendaftarkan username itu ke tabel Player atau proses registrasi dianggap gagal.

Data dimasukan ke tabel skor

Server Client

Membuka Koneksi

Mengirimkan ID_PLAYER, ID_MIDI, dan skor

Menerima ID_PLAYER, ID_MIDI

dan skor Meminta ID_MIDI

dari file yang baru

dimainkan Mengirimkan

ID_MIDI

Gambar 3.7 Protokol Submit Skor.

Pada proses submit skor, client terlebih dahulu membentuk koneksi dengan database server. Setelah koneksi terbentuk, client akan meminta ID_MIDI dari file yang telah dimainkan pemain. Server kemudian akan mengirimkan ID_MIDI yang diminta. Client kemudian mengirimkan ID_PLAYER, ID_MIDI, dan nilai skor. Server menerima data-data tersebut dan memasukannya ke dalam tabel skor.

(7)

Mengirimkan list file MIDI di server

Server Client

Membuat Koneksi

Me-list file MIDI yang ada di client

Meminta list file MIDI di server

Meminta link file MIDI yang tidak ada

di client Mengirimkan link

file MIDI yang tidak ada di client Men-download file

MIDI yang tidak ada di client

Update selesai Membuat list file

Gambar 3.8 Protokol Update.

Sama seperti proses lainnya, proses update diawali dengan membentuk koneksi ke database. Setelah koneksi terbentuk, client akan me-list file MIDI yang ada di client. Kemudian client akan meminta list file MIDI yang ada di server. Server akan mengirimkan list file MIDI yang ada di server. Setelah mendapatkan list file MIDI di server, client akan membandingkan dan me-list file- file MIDI yang tidak ada di client. Setelah file-file yang tidak ada di client sudah di-list, client akan meminta link-link dari file tersebut ke server. Client kemudian akan men-donwload file-file tersebut. Setelah proses download selesai, client akan kembali me-list file yang ada di client dan menyimpannya di “list.txt”. File

“list.txt” diperlukan karena “list.txt” ini akan dibaca supaya client tahu file apa saja yang sudah ada pada client. Setelah “list.txt” ini selesai dibuat, maka proses update telah selesai.

(8)

3.1.2.3 Perancangan Fitur Client

Fitur yang akan diterapkan pada client antara lain adalah, memainkan file MIDI, melakukan update file MIDI, dan menggunakan Kinect sebagai controller.

• Untuk memainkan file MIDI, client yang dibuat akan memanfaatkan library NAudio. NAudio ini adalah library .NET untuk audio dan MIDI yang bersifat open source. MIDI akan dimainkan sebagai background music .

• Untuk fitur update file MIDI, client yang dibuat akan memanfaatkan database server dan HTTP server. Database server akan digunakan sebagai database lagu yang tersimpan di server. Sedangkan HTTP server akan dimanfaatkan sebagai media akses client ke file-file MIDI yang ada di server.

• Untuk bisa mengunakan sensor Kinect sebagai controller, client yang dibuat akan menggunakan Kinect SDK 1.0 dari Microsoft. Pada Kinect SDK 1.0 terdapat beberapa library yang bisa digunakan untuk memudahkan penggunaan sensor Kinect.

3.2 Implementasi Sistem

Bagian ini akan menjelaskan implementasi Kinect, database dan MIDI beserta fitur-fitur yang diinginkan pada sistem dan hasil dari implementasinya.

(9)

3.2.1 Implementasi Kinect

Bagian ini akan menjelaskan program Kinect yang digunakan dan hasil implementasinya. Bagian-bagian yang akan dijelaskan adalah sebagai berikut:

• Proses dan program inisialisasi Kinect.

• Program skeleton.

• Mekanisme deteksi penekanan tombol.

Berikut adalah flowchart dari keseluruhan program Kinect yang diterapkan dalam client.

Start

Mendeteksi sensor Kinect

Lakukan inisialisasi sensor Kinect

Ada

Tidak Ada

Cek frame baru Tidak ada

Cek Skeleton Ada Tidak ada

Deteksi penekanan

tombol Tampilkan ke layar

Ada

Tidak ada

Lakukan fungsi tombol yang

ditekan Ada

Kembali

Gambar 3.9 Flowchart Program Kinect

(10)

Dari Gambar 3.9, urutan kerja dari program Kinect adalah:

• Inisialisasi sensor Kinect.

• Setiap ada frame baru, data skeleton dari frame tersebut akan ditampikan ke layar.

• Setiap ada perubahan data skeleton, maka dilakukan mekanisme pengecekan penekanan tombol.

• Apabila ada tombol yang ditekan, maka fungsi tombol tersebut akan dijalankan.

3.2.1.1 Inisialisasi Kinect

Untuk memudahkan inisialisasi Kinect, client yang dibuat menggunakan project dari microsoft yang terdapat pada Kinect SDK 1, yaitu Microsoft.Samples.Kinect.WpfViewers. Di dalam project tersebut terdapat berbagai macam tools yang langsung bisa dipakai, seperti KinectColorViewer, KinectDepthViewer, dan KinectSkeletonViewer. Sesuai namanya, masing-masing memudahkan untuk menampilkan hasil dari tiap sensor dari Kinect.

Sebelum menggunakan sensor-sensor Kinect yang diperlukan, terlebih dahulu perlu menginisialisasi atau mengaktifkan sensor-sensor tersebut. Fungsi- fungsi yang digunakan untuk mengaktifkannya adalah:

• ColorStream.Enable();

Berfungsi untuk mengaktifkan kamera RGB.

• DepthStream.Enable();

Berfungsi untuk mengaktifkan depth sensor.

• SkeletonStream.Enable();

Berfungsi untuk mengaktifkan skeleton detection.

(11)

Gambar 3.10 menunjukkan proses yang dijalankan untuk inisialisasi Kinect. Inisialisasi ini diperlukan supaya kita bisa menggunakan sensor Kinect.

Gambar 3.10 Script Inisialisasi Kinect

Pada script gambar 3.10, saat windows di-load, maka client akan menjalankan event handler Grid_Loaded. Saat Grid_Loaded dijalankan, client membuat event handler yang berjalan setiap adanya perubahan sensor kinect dengan nama event handler KinectSensorChooser1_KinectSensorChanged. Event handler tersebut berjalan setiap client mendeteksi adanya sensor Kinect baru.

Event handler tersebut mengaktifkan kamera RGB, depth sensor, dan skeleton dari Kinect tersebut. Sensor Kinect tersebut juga akan diberi event handler yang aktif setiap ada frame baru, yang akan menjalankan method newsensor_AllFramesReady.

KinectSensor _sensor;

private void Grid_Loaded(object sender, RoutedEventArgs e) {

KinectSensorChooser1.KinectSensorChanged += new

DependencyPropertyChangedEventHandler(KinectSensorChooser1_Kin ectSensorChanged);

if (KinectSensor.KinectSensors.Count > 0) _sensor = KinectSensor.KinectSensors[0];

}

void KinectSensorChooser1_KinectSensorChanged(object sender, DependencyPropertyChangedEventArgs e)

{

Try {

KinectSensor oldsensor = (KinectSensor)e.OldValue;

stop_Kinect(oldsensor);

}

catch (Exception ex)

Console.WriteLine(ex);

KinectSensor newsensor = (KinectSensor)e.NewValue;

KinectSensor newsensor = (KinectSensor)e.NewValue;

newsensor.ColorStream.Enable();

newsensor.DepthStream.Enable();

newsensor.SkeletonStream.Enable();

newsensor.AllFramesReady += new EventHandler

<AllFramesReadyEventArgs>(newsensor_AllFramesReady);

try

newsensor.Start();

catch (System.IO.IOException)

KinectSensorChooser1.AppConflictOccurred();

}

(12)

3.2.1.2 Skeleton

Bagian ini akan menjelaskan bagaimana cara menggunakan fitur skeleton dari Kinect. Berikut ini adalah script yang digunakan.

Gambar 3.11 Script Allframesready dan Getfirstskeleton

void newsensor_AllFramesReady(object sender, AllFramesReadyEventArgs e) {

Skeleton first = GetFirstSkeleton(e);

if (first == null) return;

GetCameraPoint(first, e);

}

Skeleton GetFirstSkeleton(AllFramesReadyEventArgs e) {

using (SkeletonFrame SkeletonFrameData = e.OpenSkeletonFrame()) {

if (SkeletonFrameData == null) return null;

SkeletonFrameData.CopySkeletonDataTo(allskeletons);

if (CurrentTrackingId != 0) {

skeleton = (from s in allskeletons where

s.TrackingState == SkeletonTrackingState.Tracked &&

s.Joints[JointType.Head].TrackingState ==

JointTrackingState.Tracked && s.TrackingId ==

CurrentTrackingId select s).FirstOrDefault();

if (skeleton == null) {

CurrentTrackingId = 0;

newsensor.SkeletonStream.AppChoosesSkeletons

= false;

} }

else {

skeleton = (from s in allskeletons where s.TrackingState == SkeletonTrackingState.

Tracked && s.Joints[JointType.Head].TrackingState

== JointTrackingState.Tracked select s).

FirstOrDefault();

if (skeleton != null) {

CurrentTrackingId = skeleton.TrackingId;

newsensor.SkeletonStream.AppChoosesSkeletons =true;

newsensor.SkeletonStream.ChooseSkeletons (CurrentTrackingId);

} }

return skeleton;

}}

(13)

Dari gambar 3.11, pada event handler newsensor_AllFramesReady, client akan menjalankan method GetFirstSkeleton. GetFirstSkeleton digunakan untuk mendapatkan data skeleton pemain yang terdeteksi. Setelah data skeleton diambil, data tersebut perlu ditampilkan ke layar. Client menggunakan method GetCameraPoint untuk menampilkan data skeleton tersebut ke layar. Berikut adalah script untuk menampilkan skeleton ke layar.

Gambar 3.12 Script GetCameraPoint dan CameraPosition

void GetCameraPoint(Skeleton first, AllFramesReadyEventArgs e) {

using (DepthImageFrame depth = e.OpenDepthImageFrame()) {

if (depth == null) {

return;

}

BodyDepthPoint = depth.MapFromSkeletonPoint

(first.Joints[JointType.ShoulderCenter].Position);

LeftDepthPoint = depth.MapFromSkeletonPoint

(first.Joints[JointType.HandLeft].Position);

RightDepthPoint = depth.MapFromSkeletonPoint

(first.Joints[JointType.HandRight].Position);

ColorImagePoint BodyColorPoint = depth.

MapToColorImagePoint(BodyDepthPoint.X, BodyDepthPoint.Y, colorImageFormat.

RgbResolution640x480Fps30);

ColorImagePoint LeftColorPoint = depth.

MapToColorImagePoint(LeftDepthPoint.X, LeftDepthPoint.Y, ColorImageFormat.

RgbResolution640x480Fps30);

ColorImagePoint RightColorPoint = depth.

MapToColorImagePoint(RightDepthPoint.X, RightDepthPoint.Y, ColorImageFormat.

RgbResolution640x480Fps30);

CameraPosition(BodyImage, BodyColorPoint);

CameraPosition(LeftHand, LeftColorPoint);

CameraPosition(RightHand, RightColorPoint);

cek_tangan();

} }

private void CameraPosition(FrameworkElement element, ColorImagePoint point)

{

Canvas.SetLeft(element, point.X - element.Width / 2);

Canvas.SetTop(element, point.Y - element.Height / 2);

}

(14)

Pada method GetCameraPoint, client mengambil data depth dan data koordinat dari 3 joint skeleton, yaitu ShoulderCenter (bahu tengah), HandRight (tangan kanan), dan HandLeft (tangan kiri). Data koordinat joint tersebut akan digunakan untuk meletakkan gambar di layar. Method yang digunakan untuk meletakkan gambar di layar mengunakan method CameraPosition .

3.2.1.3 Deteksi Penekanan Tombol

Untuk mendeteksi ada tidaknya penekanan tombol, diperlukan suatu metode. Metode ini harus bisa mendeteksi apabila tangan pemain berada di suatu tombol tertentu. Kemudian apabila jarak tangan pemain terhadap bahu pemain mencapai jarak yang sudah ditentukan, maka client akan menganggap kalau pemain bertujuan untuk menekan tombol tersebut.

Untuk mendeteksi apakah tangan pemain berada di suatu tombol tertentu, maka client harus terlebih dahulu mengetahui letak semua tombol yang bisa ditekan dengan tangan pemain. Untuk mengetahui letak tombol digunakan method Canvas.GetLeft() dan Canvas.GetTop(). GetLeft digunakan untuk mendapatkan koordinat X suatu tombol, sedangkan GetTop berfungsi untuk mendapatkan koordinat Y suatu tombol.

Setelah koordinat tombol didapat, maka koordinat tangan dan tombol akan dibandingkan. Berikut adalah scriptyang digunakan.

Gambar 3.13 Script Deteksi Penekanan Tombol

if (((RightX >= labelKiriX) && (RightX <= labelKiriX +

labelKiri.ActualWidth)) && ((RightY >= labelKiriY) && (RightY <=

labelKiriY + labelKiri.ActualHeight)) && (tangankanan_badan >=

Jarak_Threshold1)) {

//lakukan animasi deteksi tangan

labelKiri.FontWeight = FontWeights.UltraBold;

if (tangankanan_badan >= Jarak_Threshold) {

//lakukan penekanan tombol page = 2;

init_page();

} }

(15)

Script pada gambar 3.13 RightX berisikan koordinat X tangan kanan dan RightY berisikan koordinat Y tangan kanan. Sedangkan LabelKiriX berisikan koordinat X Label kiri dan LabelKiriY berisikan koordinat Y Label Kiri. Script berjalan bila koordinat tangan kanan sama dengan koordinat labelKiri dan juga jarak tangan kanan terhadap badan lebih besar dari Jarak_Threshold1. Apabila syarat tersebut memenuhi maka tangan kanan pemain akan dianggap berada di atas tombol dan bisa menekan tombol tersebut. Tangan kanan pemain akan dianggap menekan tombol apabila jarak tangan kanan terhadap badan lebih besar dari Jarak_Threshold.

3.2.2 Program Database

Bagian ini akan menjelaskan program yang digunakan untuk membentuk koneksi dengan database server, metode login, registrasi, dan submit skor.

3.2.2.1 Program Koneksi Database

Pada ODBC terdapat 3 tipe variable yang akan kita gunakan yaitu, OdbcConnection OdbcCommand, dan OdbcDataReader. OdbcConnection digunakan untuk membuat jaringan yang akan digunakan. OdbcCommand digunakan untuk mengirim query SQL. OdbcDataReader digunakan untuk membaca hasil query dari hasil eksekusi OdbcCommand.

(16)

Berikut adalah gambar insialisasi program ODBC.

Gambar 3.14 Contoh Program Inisialisasi ODBC

Script di atas berfungsi untuk membuka koneksi dengan database server.

Proses ini harus dilakukan terlebih dahulu dilakukan sebelum bisa mengakses database dan melakukan query. Query diperlukan karena proses login, registrasi, submit skor, dan meminta list file yang ada di server, semua menggunakan query.

System.Data.Odbc.OdbcConnection OdbcCon;

System.Data.Odbc.OdbcCommand OdbcCom;

System.Data.Odbc.OdbcDataReader OdbcDR;

bool connect_server() {

bool hasil = false;

ConStr = "DRIVER={MySQL ODBC 3.51 Driver};SERVER=localhost;

PORT=3306;DATABASE=Kinect piano;UID=root;PWD=;OPTION=3";

OdbcCon = new System.Data.Odbc.OdbcConnection(ConStr);

try {

OdbcCon.Open();

hasil = true;

}

catch (System.Data.Odbc.OdbcException Ex) {

Console.WriteLine(Ex.Message);

}

return hasil;

}

(17)

3.2.2.2 Program Login

Berikut ini adalah script yang digunakan untuk proses login.

Gambar 3.15 Script Login

Pada script di atas, username diambil dari textBox_Username, sedangkan Password diambil dari passwordBox1, apabila salah satu dari username atau password kosong, maka proses login secara otomatis dianggap gagal. Kemudian client akan melakukan query untuk meminta id_player di mana nama_pemain sama dengan username yang diisikan pemain, dan password sama dengan password yang diisikan pemain. Apabila server mengirimkan data hasil query ke client, hasil query tersebut akan disimpan dan nilai hasil akan menjadi true.

Apabila hasil bernilai true, maka proses login berhasil.

bool Login() {

if (textBox1.Text == null) return false;

if (passwordBox1.Password == null) return false;

if (!connect_server()) return false;

bool hasil = false;

try {

OdbcCom = new System.Data.Odbc.OdbcCommand("SELECT ID_PLAYER FROM player WHERE NAMA_PEMAIN =

\""+ textBox1.Text+"\" AND PASSWORD =

\""+passwordBox1.Password+"\"", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

if (OdbcDR.Read()) {

hasil = true;

Player_ID = (Int16)OdbcDR[0];

} }

catch (Exception ex) {

Console.WriteLine(ex);

}

Console.WriteLine("hasil = " + hasil);

OdbcCon.Close();

return hasil;

}

(18)

3.2.2.3 Program Registrasi

Berikut ini adalah script yang digunakan untuk proses registrasi.

Gambar 3.16 Script Registrasi

Proses registrasi hampir sama seperti dengan proses login. Username diambil dari textBox_Username, sedangkan Password diambil dari passwordBox1, apabila salah satu dari username atau password kosong, maka proses registrasi secara otomatis dianggap gagal. Kemudian client akan melakukan query untuk melakukan registrasi username dan password ke tabel player di database server. Apabila pada tabel player ternyata terdapat username yang sama, maka proses registrasi tersebut akan gagal.

bool Reg() {

if (textBox1.Text == null) return false;

if (passwordBox1.Password == null) return false;

if (!connect_server()) return false;

bool hasil = false;

try {

OdbcCom = new System.Data.Odbc.OdbcCommand("INSERT INTO player (NAMA_PEMAIN,PASSWORD) VALUES('" + textBox1.Text + "','" + passwordBox1.Password + "')", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

hasil = true;

}

catch (Exception ex) {

Console.WriteLine(ex);

}

Console.WriteLine("hasil = " + hasil);

OdbcCon.Close();

return hasil;

}

(19)

3.2.2.4 Program Submit Skor

Berikut ini adalah script untuk men-submit skor.

Gambar 3.17 Script Submit Skor

Untuk bisa men-submit skor, client akan meminta ID_MIDI dari lagu yang dimainkan kepada server, berdasarkan nama file. Setelah mendapat ID_MIDI, client akan melakukan query untuk memasukan skor ke tabel score.

Client akan mengirimkan data ID_MIDI, ID_PLAYER, dan SCORE ke database server.

bool submit_score() {

bool hasil = false;

if (!connect_server()) return false;

try {

OdbcCom = new System.Data.Odbc.OdbcCommand("SELECT ID_MIDI FROM midi WHERE NAMA_MIDI =\"" + file_name + "\"", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

if (OdbcDR.Read()) {

MIDI_ID = (int)OdbcDR[0];

hasil = true;

} else {

return false;

}

OdbcCom = new System.Data.Odbc.OdbcCommand("INSERT INTO score (ID_MIDI,ID_PLAYER,SCORE) VALUES('" + MIDI_ID + "','" + Player_ID + "','" + final_score + "')", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

hasil = true;

}

catch (Exception ex) {

Console.WriteLine(ex);

}

OdbcCon.Close();

return hasil;

}

(20)

3.2.2.5 Program Update

Berikut ini adalah script untuk melakukan update.

Gambar 3.18 Script Update

void Update_lagu() {

string[] Data_ODBC = new string[0];

labelUpdate.Visibility = Visibility.Visible;

if (!connect_server()) {

labelUpdate.Content = "Connection Failed";

labelUpdate.Visibility = Visibility.Visible;

labelOK.Visibility = Visibility.Visible;

return;

}//list file local try

list = Directory.GetFiles(@MIDI_dir);

catch (Exception ex) {

Console.WriteLine(ex);

Directory.CreateDirectory(@MIDI_dir);

}

for (int a = 0; a <= (list.Length - 1); a++)

list[a] = list[a].Remove(0, MIDI_dir.Length);

//list file server int i2 = 0;

OdbcCom = new System.Data.Odbc.OdbcCommand("select NAMA_MIDI From MIDI", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

Array.Resize(ref Data_ODBC,OdbcDR.RecordsAffected);

while (OdbcDR.Read()) {

Data_ODBC[i2] = (string)OdbcDR[0];

i2++;

}

string[] NAMA_MIDI = Data_ODBC;

//cek file server dan local

bool[] cek = new bool[NAMA_MIDI.Length];

for (int i3 = 0; i3 <= i2 - 1; i3++) {

for (int i4 = 0; i4 <= (list.Length - 1); i4++) {

if (NAMA_MIDI[i3] == list[i4]) {

cek[i3] = true;

i3++;

} else {

cek[i3] = false;

} }

}

(21)

Gambar 3.18 Script Update (sambungan 1)

//nge-list link download

string[] nama_MIDI = new string[cek.Length];

string[] link = new string[cek.Length];

int i6 = 0;

for (int i5 = 0; i5 <= i2 - 1; i5++) {

if (!cek[i5]) {

OdbcCom = new System.Data.Odbc.OdbcCommand("select

LINK_MIDI From MIDI where NAMA_MIDI = \"" + NAMA_MIDI[i5]

+ "\"", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

while (OdbcDR.Read())

{ nama_MIDI[i6] = NAMA_MIDI[i5];

link[i6] = (string)OdbcDR[0];

i6++;

} }

} //download file If (i6 != 0) {

client = new WebClient();

for (int i7 = 0; i7 <= i6 - 1; i7++)

{ try

{

WebRequest request = WebRequest.Create(new Uri(link[i7]));

request.GetResponse();

client.DownloadFileAsync(new Uri(link[i7]), @"MIDI/" + nama_MIDI[i7]);

while (client.IsBusy)

Console.WriteLine("menunggu download");

downloaded++;

labelUpdate.Content = downloaded + "/" + i6;

}

catch (WebException)

Console.WriteLine("Failed to download " + nama_MIDI[i7]);

}

} //buat list.txt

//nge-list file di client

string[] file_list = Directory.GetFiles(@MIDI_dir);

for (int a = 0; a <= (file_list.Length - 1); a++)

file_list[a] = file_list[a].Remove(0, MIDI_dir.Length);

//ngelist level file

for (int i8 = 0; i8 <= file_list.Length - 1; i8++)

{ try

{

OdbcCom = new System.Data.Odbc.OdbcCommand("select LEVEL From MIDI where NAMA_MIDI = \"" + file_list[i8] +

"\"", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

while (OdbcDR.Read())

LEVEL[i8] = Convert.ToString(OdbcDR[0]);

}

catch (Exception ex)

Console.WriteLine("level : " + ex);

}

(22)

//ngelist ID_MIDI

for (int i8 = 0; i8 <= file_list.Length - 1; i8++) {

try {

OdbcCom = new System.Data.Odbc.OdbcCommand("select ID_MIDI From MIDI where NAMA_MIDI = \"" + file_list[i8] + "\"", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

Data_ODBC = new string[OdbcDR.RecordsAffected];

while (OdbcDR.Read())

ID_MIDI[i8] = Convert.ToString(OdbcDR[0]);

}

catch (Exception ex)

Console.WriteLine("id_midi" + ex);

} //ngelist highscore

for (int i8 = 0; i8 <= file_list.Length - 1; i8++) {

try {

OdbcCom = new System.Data.Odbc.OdbcCommand("select MAX(SCORE) as MAX_SCORE From SCORE where ID_MIDI = \""

+ ID_MIDI[i8] + "\"", OdbcCon);

OdbcDR = OdbcCom.ExecuteReader();

Data_ODBC = new string[level.Length];

while (OdbcDR.Read())

Data_ODBC[i8] = Convert.ToString(OdbcDR[0]);

}

catch (Exception ex)

Console.WriteLine("score :" + ex);

string[] HighScore = Data_ODBC;

} //tulis ke list.txt

using (StreamWriter sw = new StreamWriter(@Dir + "\\list.txt")) {

for (int i8 = 0; i8 <= file_list.Length - 1; i8++) {

if ((file_list[i8] != null) && (LEVEL[i8] != null)

&& (HighScore[i8] != null)) {

sw.WriteLine(file_list[i8] + ":" + LEVEL[i8]

+ ":" + HighScore[i8]);

} else {

try {

File.Delete(@MIDI_dir + "//" + file_list[i8]);

}

catch (IOException ex)

Console.WriteLine(ex);

} }

}

OdbcCon.Close();

}

(23)

Dari script update pada gambar 3.18, client terlebih dahulu mencoba membuka koneksi, apabila gagal, update otomatis gagal. Client kemudian me-list file yang ada di client dan server, kemudian dibandingkan. Setiap file yang tidak ada di client akan di-download. Setelah file-file tersebut selesai di download, client perlu me-list ulang file di client ke “list.txt”. Data yang akan disimpan dalam “list.txt” ini adalah nama file, level, dan highscore dari MIDI tersebut.

Tetapi untuk bisa mendapatkan data highscore, diperlukan ID_MIDI, oleh karena itu client harus terlebih dahulu mengambil ID_MIDI.

3.2.3 Program MIDI

Bagian ini akan menjelaskan program yang digunakan untuk memainkan file MIDI, mengeluarkan nada MIDI, animasinya dan perhitungan skor.

3.2.3.1 Membuka File MIDI

Pada saat file MIDI di baca, data-data yang perlu diambil dan disimpan adalah, data message tiap track, data time division, dan delay per 1 delta time.

Delay per 1 delta time bisa didapat dengan menggunakan rumus berikut:

⁄ (3.1)

Delay yang didapat adalah delay dalam satuan tick atau 100 ns. Tempo dikalikan 10 karena data tempo dalam satuan ms, karena itu untuk dijadikan dalam satuan tick harus dikalikan dengan 10.

(24)

Berikut ini adalah flowchart dari program untuk membuka MIDI.

Gambar 3.19 Flowchart Program Membuka MIDI

(25)

Berikut ini adalah script untuk membuka file MIDI.

Gambar 3.20 Script Untuk Membuka File MIDI

Pada script di atas, file MIDI dibuka dan disimpan ke variabel “file”.

Kemudian DeltaTicksPerQuaterNote dari file akan disimpan.

DeltaTicksPerQuarterNote ini diperlukan untuk melakukan perhitungan delay per 1 delta time. Kemudian semua data event dari file tersebut akan disimpan di alleventcolection. Data event tiap track akan disimpan di array track dan akan digabung kembali di all_track. Data di dalam all_track perlu di-sorting apabila file MIDI tersebut tidak menggunakan format file MIDI 0. Setelah di-sorting, maka data pada all_track siap digunakan.

public static MidiEvent[][] track;

public static MidiEvent[] all_track;

static float delta_time_s = 50000000;

public static int delta_per_quarter = 1;

void open_midi(string file_location) {

IList<MidiEvent> midievent = new List<MidiEvent>();

MidiFile file = new MidiFile(file_location);

int delta_per_quarter = file.DeltaTicksPerQuarterNote;

MidiEventCollection alleventcolection = file.Events;

Array.Resize(ref track, file.Tracks);

for (int n_track = 0; n_track < file.Tracks; n_track++) {

IList<MidiEvent> track_data = alleventcolection.

GetTrackEvents(n_track);

track[n_track] = track_data.ToArray<MidiEvent>();

}

for (int n_track = 0; n_track < file.Tracks; n_track++) {

Array.Resize(ref all_track, (all_track.Length + track[n_track].Length));

Array.Copy(track[n_track], 0, all_track, (all_track.Length - track[n_track].Length), track[n_track].Length);

}

if (file.FileFormat > 0) {

var sorted = all_track.OrderBy(item => item.AbsoluteTime);

all_track = sorted.ToArray<MidiEvent>();

} }

(26)

3.2.3.2 Memainkan File MIDI

Berikut adalah script dan flowchart yang digunakan untuk memainkan file MIDI

Start

Melakukan delay 1 delta time

Mengecek message ke -Msg

Time >=

message absoulte time Nilai Time = 0 Animasi = 0

Msg =0

Time+1 dan Animasi+1

Memainkan message

Msg +1 Ya

Tidak

Animasi == 10 Tidak

Menurunkan canvas animasi Animasi = 0

Ya

Gambar 3.21 Flowchart Program Memainkan File MIDI

(27)

Gambar 3.22 Script Untuk Memainkan File MIDI

Void play_midi() {

midi_thread = new Thread(thread_start);

midi_thread.Priority = ThreadPriority.Highest;

midi_thread.Start();

}

public void thread_start() {

hitung1 = 0;

Time = 0;

int delay_animasi = 0;

try {

while (true) {

Thread.Sleep(delay_midi);

Time++;

delay_animasi++;

bool cek = true;

while (cek) {

if (all_track[hitung1].AbsoluteTime <= Time) {

midiOut.Send(all_track[hitung1].GetAsShortMessage());

if (all_track[hitung1].GetType() == tempo.GetType()) {

tempo = (TempoEvent)all_track[hitung1];

delta_time_s = tempo.MicrosecondsPerQuarterNote;

delta_time_s = (delta_time_s * 10) / delta_per_quarter;

delay_midi = new TimeSpan((long)delta_time_s);

}

hitung1++;

} Else

cek = false;

}

if (delay_animasi == 10) {

delay_animasi = 0;

this.Dispatcher.Invoke((Action)(() =>

{

Canvas.SetBottom(canvas2, (Canvas.GetBottom(canvas2)- 1));

}));

} } }

catch(Exception) {

this.Dispatcher.Invoke((Action)(() =>

{

page = 2;

init_page();

}));

midi_thread.Abort();

} }

(28)

Pada script di atas, client menggunakan thread untuk memainkan file MIDI. Thread digunakan supaya client utama bisa lebih leluasa mengerjakan proses lain, seperti proses Kinect, mencatat skor dan lainnya. Thread perlu diberi priority yang tinggi agar MIDI yang dimainkan tidak terdengar putus-putus.

Pertama thread melakukan delay 1 delta time, kemudian mengecek message berikutnya. Apabila absolute time dari message berikutnya sama dengan nilai waktu permainan, maka message itu akan dimainkan dengan cara mengeluarkan data message ke midiout. Setiap message harus dicek, apakah message tersebut adalah Tempo Event. Hal ini perlu, karena apabila Tempo Event diabaikan , maka delay per 1 delta time tidak sama dengan yang seharusnya, sehingga musik yang dimainkan terdengar aneh.

3.2.3.3 Animasi Permainan

Animasi yang akan dibuat ialah animasi piano yang memiliki 2 oktaf not berserta not kromatis. Animasi yang dibuat adalah not-not yang turun dari atas, dan apabila sudah mencapai suatu garis, maka not tersebut harus ditekan oleh pemain. Apabila pemain gagal menekan not dengan tepat, maka pemain tidak akan mendapatkan penambahan skor.

Metode pemilihan not yang akan dimainkan ialah sebagai berikut:

• Apabila message tersebut ialah patch change message yang nilai patch- nya antara 0-7, maka flag untuk channel tersebut bernilai true, sedangkan bila tidak bernilai 0-7, maka flag untuk channel tersebut bernilai false.

• Apabila message tersebut adalah note on message, nilai not yang dimainkan bernilai antara 60 sampai dengan 83 dan flag untuk channel dari message tersebut bernilai true, maka akan dibuat kotak animasi untuk not tersebut di canvas animasi.

(29)

• Berikut adalah flowchart dan script yang digunakan untuk menyiapkan not-not yang akan ditekan.

Gambar 3.23 Flowchart Mekanisme Pemilihan Not

Gambar 3.24 Script Mekanisme Pemilihan Not

foreach (MidiEvent a in all_track) {

if (a.GetType() == patch.GetType()) {

patch = (PatchChangeEvent)a;

if (patch.Patch <= 7 && patch.Patch >= 0) patched_channel[patch.Channel-1] = true;

else

patched_channel[patch.Channel-1] = false;

}

if (MidiEvent.IsNoteOn(a)) {

if (patched_channel[a.Channel-1]) {

NoteOnEvent ab = (NoteOnEvent)a;

if (ab.NoteNumber >= 60 && ab.NoteNumber <= 83) {

kotak[kot] = new Rectangle();

kotak[kot].Height = 2;

kotak[kot].Width = 22;

kotak[kot].Fill = redBrush;

Canvas.SetBottom(kotak[kot], a.AbsoluteTime / 10);

Double left = (ab.NoteNumber - 60) * 22;

Canvas.SetLeft(kotak[kot], left);

canvas2.Children.Add(kotak[kot]);

kot++;

}}}}

(30)

3.2.3.4 Perhitungan Skor

Dalam permainan ini terdapat fitur perhitungan skor yang digunakan untuk mengetahui ketepatan permainan. Metode yang digunakan ialah membandingkan letak kotak animasi dengan waktu permainan. Berikut adalah script yang digunakan.

Gambar 3.25 Script Perhitungan Skor

Script di atas berjalan di dalam thread MIDI. Apabila waktu permainan sudah mencapai tinggi kotak permainan, maka nilai tekan_nada menjadi true, tetapi apabila waktu permainan sudah melebihi tinggi kotak permainan maka nilai tekan_nada menjadi false. Apabila pemain menekan tombol saat tekan_nada bernilai true, maka skor permain bertambah.

public bool[] tekan_nada = new bool[24];

bool cek_nada = true;

int cek_ke = 0;

while (cek_nada) {

this.Dispatcher.Invoke((Action)(() =>

{

if ((hitung_nada + cek_ke) < kotak.Length) {

double tinggi = Canvas.GetBottom(kotak[hitung_nada + cek_ke]);

if ((tinggi == ((double)Time / 10) - 5)) {

double kiri = Canvas.GetLeft(kotak[hitung_nada + cek_ke]);

tekan_nada[(int)(kiri / 22)] = true;

cek_ke++;

}

else if (tinggi == ((double)Time / 10) + 5) {

double kiri = Canvas.GetLeft(kotak[hitung_nada + cek_ke]);

tekan_nada[(int)(kiri / 22)] = true;

hitung_nada++;

} Else {

cek_nada = false;

} } Else

cek_nada = false;

}));

}

Referensi

Dokumen terkait

Pada saat Peraturan Badan ini mulai berlaku, Peraturan Kepala Badan Narkotika Nasional Nomor 5 Tahun 2010 tentang Pedoman Teknis Penyelenggaraan Pelayanan

dilaksanakan Rapat dengan agenda Evaluasi Program Kerja. Untuk itu dimohon kepada setiap bidang-bidang mempersiapkan laporan hasil kinerja. Dan diharapkan kepada semua

 Keunggulan kompetiti. Sebuah arsitektur kepatuhan yang luas dan konsisten dapat memungkinkan suatu perusahaan untuk lebih memahami dan mengendalikan proses bisnis mereka,

Dengan demikian maka untuk perkembangan masyarakat yang dinamis, seluruh potensi dan kekuatan jiwa kewiraswastaan yang ada harus secara gradual namun ajeg diarahkan

Upaya yang dilakukan oleh Pengawas Madrasah Tsanawiyah di Kabupaten Jepara untuk memperbaiki kualitas proses pembelajaran dalam meningkatkan mutu hasil pembelajaran

Keterampilan kerja, atau disingkat dengan keterampilan ialah tingkat kemampuan untuk melakukan suatu pekerjaan atau suatu bagian pekerjaan, yang hanya

Penelitian ini bertujuan untuk mengetahui pengaruh penggunaan subtrat yang dapat mempengaruhi jumlah fekunditas ikan mas koki oranda (Carassius auratus Linnaeus),

Hasil survei awal 3 di Puskesmas II Denpasar Selatan pada Bulan April-Juni 2011 ditemukan anemia sebanyak 27 (57,4%) dari 47 ibu hamil, dengan faktor yang