Search Here

Sunday, March 22, 2015

Comparing Audio files with Sense

Hello Readers,

This week, I did an interesting (at least to me) experiment and study about how to compare the Audio files (Audio data).

Background

@Rajesh  is my good friend at @Work and my morning walk buddy. He is a hard core Electronics guy , He gives lots of gyan about the Radio waves, AM signals etc etc .. Mostly I wont get it but he is patient enough to explain in plain words which can be understood by a computer science engineer (its me :)).

@work, we are working on Digital Radios, To simplify the scenario, imagine,

1. Radio station pick up the song - Which may be raw PCM data / Compressed as high quality MP3

2. Radio station transmits the song over the Air

3. Your home radio box receives it and reproduce the same Song - By now, it wont be in original file format

4. You will hear the song with acceptable quality

5. Great

@Work in the labs we simulate this situation with various equipments and test the song received is in acceptable quality.

@Rajesh, explain me the pain of this testing. Everytime  we need to literally sit and listen the song to know that radio receiver is working fine and reproducing the song with good quality.

The main issue is that Songs / Real life record content is totally different than the audio test vectors (Ex: Sine wave tone). Some of the problems will only occurs to the Songs but in the same setup Sine wave tone works fine.

Obviously, @Rajesh told more about electronics and behaviour of the Radio Signals. I wont explain here (until I get to know it properly :) ).

We were talking about automation of audio listening tests. Due to the nature of the audio data, we can not compare them as a file comparison. Moreover in our situation, Source and Destination audio format is changing and Audio quality also changing. Opps lots of variables.

@Rajesh asked me to find some way to test it.
 
I was approching this problem from the computer science point of view.

My first thought was, we need to have some model which is similar to human ears. Irrespective of audio file format, quality changes, Humans can find out the similar songs.

Obviously, Google is the best friend while learning. I knew that, there are lots of music recognition applications available in mobile world. I have used Shazam, It could identify the songs properly.

I never gave a good thought about how Shazam kind of applications are working but now its needed for me.

I learnt that Shazam kind of music recognition apps are working using Acoustic fingerprint algorithms.

There are many Acoustic fingerprint algorithms are available. I chose the open source chromaprint algorithm developed by Lukáš Lalinský.

chromaprint converts the song / music as a musical notes and creates the fingerprints for various parts of the song. So the file format change and quality change is least affects this algorithm. Its a brilliant idea.

Read How chromaprint works, if you really interested in the algorithm.

chromaprint provides the pre built tool called fpcalc. fpcalc used to calculate the acoustic fingerprint. To install the fpcalc in Fedora linux,


1
2
3
4
5
6
[root@bakkisweety ~]# yum install libchromaprint-devel chromaprint-tools libchromaprint
Loaded plugins: langpacks, show-leaves, upgrade-helper
Package libchromaprint-devel-1.1-3.fc21.x86_64 already installed and latest version
Package chromaprint-tools-1.0-6.fc21.x86_64 already installed and latest version
Package libchromaprint-1.1-3.fc21.x86_64 already installed and latest version
Nothing to do


1
2
3
[root@bakkisweety Audacity]# fpcalc -version
fpcalc: /usr/lib64/nvidia-304xx/libOpenCL.so.1: no version information available (required by /lib64/libavutil.so.54)
fpcalc version 1.1.0

Note: Ignore the warning message from fpcalc

Now, I have a tool to find the acoustic fingerprints. I also need some test data to proceed. I have downloaded a public available song from youtube as MP3 and also recorded my own voice using Audacity.

If you like to work on MP3 files directly in Audacity, You need to install,


1
2
3
4
[root@bakkisweety ~]# yum install audacity-freeworld.x86_64
Loaded plugins: langpacks, show-leaves, upgrade-helper
Package audacity-freeworld-2.0.6-1.fc21.x86_64 already installed and latest version
Nothing to do


The normal Audacity package is not having support to import MP3 / MP4 audio.

I have created following files using Audacity,

1. hello_10.wav - My hello voice. Total length 10 sec


2. hello_10.mp3 - hello_10.wav is converted as a MP3 file


3. hello_10_noise1.wav - hello_10.wav, Added more noise in middle and small point in beginning.


4. hello_10_less_noise.wav - hello_10.wav, with less noise added.



Tools are installed, Test audio files are available, Lets starts the experiment,


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[root@bakkisweety Audacity]# fpcalc hello_10.wav 
fpcalc: /usr/lib64/nvidia-304xx/libOpenCL.so.1: no version information available (required by /lib64/libavutil.so.54)
FILE=hello_10.wav
DURATION=10
FINGERPRINT=AQAAQWOiRRojodY0IZG-J0Eq7YLDo3cR86C4i5CbHXkvoXeRqVq4IDkfWL2EpmmK-0HYBUyebpA7HfmFOumERLryJEilXXB49C5iHg2XE1JWpkOuC3VuZKqmLUjOPbB6oQnTVDh9fDkyPd0gdzryC3XSItMVLgkS67hOVHUR82jIE1L2dMh1oc6NtJq2QDL3IFUvNKGPpym-Pch0b5AbIb-E3kWmKgoXIbE-XCeqNsXpIyxPAAGEA8wQQ4BQAgEEjBRAOMAQBEgQAYBBCBgpGBIMEQgQEQIBhIwDDAkAEA
[root@bakkisweety Audacity]# fpcalc hello_10.mp3 
fpcalc: /usr/lib64/nvidia-304xx/libOpenCL.so.1: no version information available (required by /lib64/libavutil.so.54)
FILE=hello_10.mp3
DURATION=10
FINGERPRINT=AQAAQWOiKNIYCXUyTUIifVeQSrvQhMddxDwo7iLkZkfeS-hdZKoWLkgsfoF_ognTFKePsMsJJk8HudORX6iTaUKm70mQUNrh8ETvIubRcLkIKWeO_LpQxzXSal2QyJwXWD2aME2F08eXI9PTDXKnI79QJy0yfVyCxPKJ60RVFzGPhssJKSvTIdeF50ZTTVuQyNyDVL3QhD6epvj2INO9QW6E_BJ6F5mqjEuCxPJxneib4j7CkCcAAYRTzBBDAAECAISAkQIYAxgRAgggADAIASMFQIIhCBAiQiCAkHEAIAEQQAA
[root@bakkisweety Audacity]# fpcalc hello_10_noise1.wav
fpcalc: /usr/lib64/nvidia-304xx/libOpenCL.so.1: no version information available (required by /lib64/libavutil.so.54)
FILE=hello_10_noise1.wav
DURATION=10
FINGERPRINT=AQAAQWOiKNIYCXXSCYl05UmQSrvg8Ohd5IezXYTEZjny6hJ6F5mqdUFy7oFVWWjyVPiDNsrRPJWKF0f4HuLH42GPTF-F5xeqoz3chCQ-HPmQ_PhOoaZwfqi1ywhzpobc6cgv9C4yVVG4JEis4zpR1UXMoyFPMHs6JNeF50ZTTSMSmbuCVL3QhMfjIt4O6hYhN0feS-hdZKqicBES6_gl1GmK-wjLAwGEA4YZYQAQxFCAEFMCCGIMAMBoiUQWAiCBBABGAoYEQ8QBhIBwCCFlCJBMIIAA
[root@bakkisweety Audacity]#


Ok. We have some acoustic fingerprints data but what do with this data. This acoustic fingerprints are encoded with specific format. We need a RAW acoustic fingerprints. Lets get the RAW acoustic fingerprints,


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
[root@bakkisweety Audacity]# fpcalc hello_10.wav -raw
fpcalc: /usr/lib64/nvidia-304xx/libOpenCL.so.1: no version information available (required by /lib64/libavutil.so.54)
FILE=hello_10.wav
DURATION=10
FINGERPRINT=1445291460,1450701268,1375130111,1369883486,1353107262,1357172526,1348782959,1092933959,1126558149,1445293508,1449616852,1475801597,1375130622,1353106270,1357238126,1365560174,1365571967,1126693191,1109748165,1445293508,1450668500,1375130111,1369883486,1353107262,1357172526,1348782959,1097136479,1126689221,1176857028,1449485780,1475867133,1375130622,1369883486,1357238062,1348782958,1365571950,1126693191,1109748165,1445293508,1449619924,1375130109,1370936190,1353107326,1357172526,1348782959,1097132383,1126689221,1176857028,1449485780,1475867125,1375130623,1369883486,1353172782,1357171502,1365563758,1126553927,1126525381,1445293508,1449616852,1408684541,1370936190,1353107326,1357238062,1348782958,1097132415

[root@bakkisweety Audacity]# fpcalc hello_10.mp3 -raw
fpcalc: /usr/lib64/nvidia-304xx/libOpenCL.so.1: no version information available (required by /lib64/libavutil.so.54)
FILE=hello_10.mp3
DURATION=10
FINGERPRINT=1445293508,1467478484,1375130111,1369883486,1353107246,1357172526,1348782959,1092933959,1126558149,1445293508,1449616852,1475801597,1370936190,1353106270,1357238062,1348782958,1097136511,1126693191,1109748165,1445293508,1450701268,1375130109,1370932062,1353107262,1357172526,1348782959,1092942175,1126689093,1176857028,1449616852,1475867125,1370936318,1369883486,1357238062,1348782958,1365571950,1126693191,1109748165,1445293508,1449619924,1442206205,1370936190,1353107326,1357172526,1348782959,1097136479,1126689221,1176857028,1449485764,1475867124,1375130623,1369883486,1353172782,1357171502,1365563758,1126553927,1126525381,1445293508,1449616852,1375097341,1370936190,1353107326,1357238126,1348782958,1097132383

[root@bakkisweety Audacity]# fpcalc hello_10_noise1.wav -raw
fpcalc: /usr/lib64/nvidia-304xx/libOpenCL.so.1: no version information available (required by /lib64/libavutil.so.54)
FILE=hello_10_noise1.wav
DURATION=10
FINGERPRINT=1445293508,1450668500,1375130111,1369883486,1353107262,1357172526,1348782895,1092933967,1126689221,1445293508,1449616852,1475867133,1375130622,1369867102,1357218606,1365541678,1348777278,-718818034,-718953202,-718951154,-735593185,-197747395,-734078147,-730969324,-781317164,-714208380,-680654444,-696314444,-696307276,-687918668,-692637259,-692767818,-744148490,-744196634,-773554842,1399122294,1126693191,1109748165,1445293508,1449616852,1375130109,1370936190,1353107326,1357172526,1348782959,1097132383,1126689223,1176857028,1449485764,1467478516,1375130623,1369883486,1353107246,1357171502,1348786543,1092999495,1126558149,1445293508,1449616852,1408684541,1375130494,1353106302,1357238126,1348782958,1365567871
 
[root@bakkisweety Audacity]# fpcalc hello_10_less_noise.wav -raw
fpcalc: /usr/lib64/nvidia-304xx/libOpenCL.so.1: no version information available (required by /lib64/libavutil.so.54)
FILE=hello_10_less_noise.wav
DURATION=10
FINGERPRINT=1445293508,1450668500,1375130111,1369883486,1353107262,1357172526,1348782895,1092933967,1126689221,1445293508,1449616852,1475867133,1375130622,1369883486,1357236014,1365561134,1365571966,1395128654,1445324878,1445325006,1445428447,1429624063,1362515327,1348880221,1357270604,1353075276,1369725916,1474587644,1449422308,1450468836,1475858924,1375130622,1369883486,1357367086,1357171502,1365571950,1126684999,1109748165,1445293508,1449616852,1375130109,1370936190,1353107326,1357172526,1348782959,1097132383,1126689223,1176857028,1449485764,1467478516,1375130623,1369883486,1353107246,1357171502,1348786543,1092999495,1126558149,1445293508,1449616852,1408684541,1375130494,1353106302,1357238126,1348782958,1365567871


Sweet, Now we have some numerical data. But still we need to make sense out this numerical data. For my situation, I need to see that two songs (one from the source which is radio station and other from radio receiver) are matching with in the threshold. For sure, The two songs wont be same.

Lets consider the numerical (signed 32bit integers) fingerpoint data as a data sets. So we have two sets in our hand. I choose the R Square assess of goodness of fit method.

In my situation, Since the source song and destination song content is same, I should get a positive correlation and in ideal lab conditions, R square should be 1.0 but so many things will happen during the radio transmission. So we can't get 1.0 but the it should be grater than 0.0. If I get 0.0 as a R square, something really wrong happen during the trasnmission.

Dont ask me why I have chose goodness of fit statistics method instead of something in electronics domain like FFT and its derivatives... I yet to test it with real data. I chose it based on pure instinct.

I wrote a perl script to do the whole process of running fpcalc to get the fingerprints, Calculate the R square and report the goodness of fit. Here is the script,


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/env perl
#Script to calculate the similarity of the two audio files using chromaprint fingerprint algorithem 
#License: LGPL2.1+
#Author: Bakkiaraj M [http://npointsolutions.blogspot.in/]
#Usage: audio_chromaprint_diff.pl audio1_file audio2_file
#Note: Install the fpcalc tool version 1.1 before you run this script 

#Refer URLs
#Refer: http://acoustid.org/chromaprint
#Refer: http://en.wikipedia.org/wiki/Coefficient_of_determination

use strict;
use warnings;
use Statistics::LineFit;
use Data::Dumper;
use Capture::Tiny ':all';

#Globals
my $fp1ArrRef;
my $fp2ArrRef;
my $audioLen = 9999; #Len in secs for fingerprint calculation. Just give rough high number. Later enhance based on songs.

my $fpcalctool = '/usr/bin/fpcalc -raw -length '.$audioLen.' ';

#Get the file names from the command line 
my $fn1 = $ARGV[0];
my $fn2 = $ARGV[1];

my $fn1FPs = 0;
my $fn2FPs = 0;
my $fpDiff = 0;

if (!defined ($fn1) or !defined ($fn2))
{
 print "\n Usage: perl $0 audio_file1 audio_file2";
 exit (-1);
}

if (! -s $fn1 or ! -s $fn2)
{
 print "\n ERROR: $fn1 or $fn2 is not a proper file.";
 exit (-1);
}


#Function
sub calcFingerPrint
{
 my $fileName = shift @_;
 
 #print "\n EXEC: $fpcalctool \"$fileName\"";
 
 my ($fpdata, $stderr, $exit) = capture {
  
        system( $fpcalctool.' "'.$fileName.'"' );
     };
    
    unless ($exit == 0)
    {
     print "\n ERROR: While running fpcalc tool";
     print "\n CMD: ",$fpcalctool.' "'.$fileName.'"';
     print "\n STDERR: ", $stderr;
     exit ($exit);
    }
    
 if ($fpdata =~m/FINGERPRINT=(.*)/g)
 {
  my @fpDataArray = ();
     @fpDataArray = split (/,/,$1);
     return \@fpDataArray;
 }
 else
 {
  return [];
 }
}

$fp1ArrRef = calcFingerPrint($fn1);
$fn1FPs = scalar @$fp1ArrRef;
$fp2ArrRef = calcFingerPrint($fn2);
$fn2FPs = scalar @$fp2ArrRef;

#$,=" ";
print "\n File1: $fn1 Tot FPs ",$fn1FPs;
#print "\n ", @$fp1ArrRef;
print "\n File2: $fn2 Tot FPs ", $fn2FPs;
#print "\n ", @$fp1ArrRef;

if ($fn1FPs != $fn2FPs)
{
 #Equalise th array items , so it will be equal.
 if ($fn1FPs > $fn2FPs)
 {
  splice ($fp1ArrRef,$fn2FPs);
 }
 else
 {
     splice ($fp2ArrRef,$fn1FPs);
 }
    print "\ Note: File1 & File2 have different FingerPrints, Lowest number of Fingerprints will be used in R2"; 
}



my $lfit = Statistics::LineFit->new();
$lfit->setData($fp1ArrRef, $fp2ArrRef);

printf "\n\n Goodnees of fit R2 for File1 & File2 = %.8f \n", $lfit->rSquared();

exit (0);

This script takes the two audio files and calculate the goodness of fit based on the acoustic fingerprints data. Lets run it,


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
[root@bakkisweety Audacity]# /mnt/WinD/Eclipse_WorkSpace/PerlExamples/audio_chromaprint_diff.pl hello_10.wav hello_10.mp3 

 File1: hello_10.wav Tot FPs 65
 File2: hello_10.mp3 Tot FPs 65

 Goodnees of fit R2 for File1 & File2 = 0.92182237 
[root@bakkisweety Audacity]# /mnt/WinD/Eclipse_WorkSpace/PerlExamples/audio_chromaprint_diff.pl hello_10.wav hello_10_less_noise.wav 

 File1: hello_10.wav Tot FPs 65
 File2: hello_10_less_noise.wav Tot FPs 65

 Goodnees of fit R2 for File1 & File2 = 0.50358946 
[root@bakkisweety Audacity]# /mnt/WinD/Eclipse_WorkSpace/PerlExamples/audio_chromaprint_diff.pl hello_10.wav hello_10_noise1.wav 

 File1: hello_10.wav Tot FPs 65
 File2: hello_10_noise1.wav Tot FPs 65

 Goodnees of fit R2 for File1 & File2 = 0.02005060 


The output clearly shows that my method of comparing the audio files is not greatly affected by the audio file formats (MP3 / WAV).

When I calculate the goodness of fit for hello_10.wav & hello_10.mp3, I get 92%, which shows that these are almost same songs.

When  more noise added the goodness of fit goes low.

I have also tested with real songs / music files. The outcome is convincing.

Can we automate the audio listening test with this approach?

Yes. we need to already set the goodness of fit tolerance level before we start the audio listening test.

Goodness of fit tolerance level is based on the source song, compressing techniques, transfer medium (AM / FM) etc ... Which I still need to workout.

I hope, with this method, we can reduce the human audio listening times during the testing.

Nevertheless, Nothing can replace human ears when it comes to music / audio testing. The above kind of methods only assists and provides the likely hood of problematic test vectors.

I will update once I work real captured data in the lab.

If this method works well, I am planning to create a perl module to wrap the libchromaprint functionality. so we can call the fpcalc as a perl function instead of subprocess.

Bye Bye ...   







 











 

Sunday, March 8, 2015

Notify to your user in Linux - GNotification

Hello Readers,

In the last post, I was referring to GNotification. Here is the dedicated post of my experiments with GNotification APIs with Perl.


Notification - A pop up message to show the quick details about what is going in the application. Usually in both linux and windows, The notifications are shown in lower right corner (system tray) of the desktop. In Linux GNOME desktop, its usually upper right corner.

Linux KDE desktop notification looks something like this,



Note: The notification appearance may vary based on the theme that you set in your desktop.

In Windows OS, Desktop notification looks something like this,



I was looking for a good way to notify from my perl application to user in Linux. In windows os, There is only one way to do. Call windows APIs yourself. But we are in free world, Linux, We have more than one way to do.

1. GNotification - Notification APIs provided by GNOME and tightly coupled for GTK applications but not hard to use in any applications even command line application. The main advantage of the GNotification APIs is its a persistence notification. Even after the system crash / reboot user will see the notification until they respond to it.

GNotification can also create notifications like questions that user can respond.

2. Libnotify - Notification APIs provided by GNOME. Very simple to use and its kind of standalone api set not tightened up with GTK. Simple and less powerfull.

We will use the GNotification API with Perl application with the help of our best foreign library interaction perl module - FFI::Platypus.
 
GNotification Way of Working is,

1. Create a new GTK application and gets its application ID

2. Register the application

3. Create Notifications

4. Set the Notification parameters

5. Show the Notifications to the user

6. Clean up everything.

Note: If you write a native GTK application, Step #1, #2 is not necessary because its implicit.

Ok. Enough talking, Here is the code.


  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
#!perl
#Description: Create GNOME Desktop notifications using GNOME libgio library and FFI::Platypus
#Refer: https://developer.gnome.org/gio/2.42/gio-GNotification.html
#Author: Bakkiaraj Murugesan
use strict;
use warnings;
use FFI::Platypus;
use FFI::Platypus::Declare;
use FFI::CheckLib;
use Data::Dumper;

$|++;
my $ffiObj = "";

print "\n Perl FFI::Platypus Gnome Notification Example";
#Find the lib
my $libPath =  find_lib( lib => '*', verify => sub { $_[0] =~ /^gio-2\.[0-9]+/ },libpath=>'/usr/lib64' );
my $gobjectLibPath = find_lib(lib=>'*',verify => sub { $_[0] =~ /^gobject-2\.[0-9]+/ },libpath=>'/usr/lib64');
my $glibLibPath = find_lib(lib=>'*',verify =>sub { $_[0] =~m/^glib-2\.\d+/;},libpath=>'/usr/lib64');

#Find the library Paths
print "\n Found libgio-2.0 in :", $libPath;
print "\n Found libgobject-2.0 in :", $gobjectLibPath;
print "\n Found libglib-2.0 in :", $glibLibPath;

#Create FFI::Platypus object
$ffiObj = FFI::Platypus->new();
$ffiObj->lang('C'); #FFI supports more than C language
$ffiObj->lib($libPath);

my $ffiObj1 = FFI::Platypus->new();
$ffiObj1->lang('C'); #FFI supports more than C language
$ffiObj1->lib($gobjectLibPath);

my $ffiObj2 = FFI::Platypus->new();
$ffiObj2->lang('C'); #FFI supports more than C language
$ffiObj2->lib($glibLibPath);

#Create gapplication
#g_application_new (const gchar *application_id,GApplicationFlags flags);
$ffiObj->attach('g_application_new',['string','int'],'opaque');

#Check application ID is valid 
$ffiObj->attach('g_application_id_is_valid',['string'],'int');
#Set GApplication Name
my $appName = 'perl.ffi.platypus.gnome.notify.example';
print "\n App Name $appName is valid? ",g_application_id_is_valid($appName); 
#G_APPLICATION_FLAGS_NONE is 0
my $GApplicationPrt = g_application_new ($appName,0);

#Register the application
#gboolean g_application_register (GApplication *application, GCancellable *cancellable, GError **error);
$ffiObj->attach('g_application_register',['opaque','opaque','opaque'],'int');
#GCancellable *g_cancellable_new (void);
#$ffiObj->attach('g_cancellable_new',['void'],'void');
#my $GCancellablePtr = g_cancellable_new();
print "\n Application Registration ID:", g_application_register($GApplicationPrt,undef,undef);

print "\n Send Welcome notification";
#Create GNotification                        
#GNotification *g_notification_new (const gchar *title);
$ffiObj->attach('g_notification_new',['string'],'opaque');
my $GNotificationPtr = g_notification_new('Welcome');

#void g_notification_set_body (GNotification *notification, const gchar *body);
$ffiObj->attach('g_notification_set_body',['opaque','string'],'void');

g_notification_set_body ($GNotificationPtr, "Welcome to GNotifications using perl + FFI::Platypus...");

#void g_application_send_notification (GApplication *application, const gchar *id, GNotification *notification);
$ffiObj->attach('g_application_send_notification',['opaque','string','opaque'],'void');
g_application_send_notification($GApplicationPrt,'perl.ffi.platypus.gnome.notify.welcome',$GNotificationPtr);

print "\n Send Urgent notification";
#void g_notification_set_urgent (GNotification *notification, gboolean urgent);
$ffiObj->attach('g_notification_set_priority',['opaque','int'],'void');
$GNotificationPtr = g_notification_new('Urgent');
g_notification_set_body ($GNotificationPtr, "This is Urgent Notification. Have a look at me!");
g_notification_set_priority($GNotificationPtr,2);
g_application_send_notification($GApplicationPrt,'perl.ffi.platypus.gnome.notify.urgent',$GNotificationPtr);

print "\n Notification with Buttons";
$GNotificationPtr = g_notification_new('Wanna Coffee?');
g_notification_set_body ($GNotificationPtr, "Would you like to drink Coffee?");

                 
#void g_notification_add_button (GNotification *notification,const gchar *label,const gchar *detailed_action);
$ffiObj->attach('g_notification_add_button',['opaque','string','string'],'void');
g_notification_add_button ($GNotificationPtr, "Ok. Sure", "app.ok");


g_application_send_notification($GApplicationPrt,'perl.ffi.platypus.gnome.notify.coffee',$GNotificationPtr);
                        
print "\n Clean Up everything";
#Do clean up
#void g_object_unref (gpointer object);
$ffiObj1->attach('g_object_unref',['opaque'],'void');
g_object_unref ($GNotificationPtr);
g_object_unref ($GApplicationPrt);

print "\n Ta Ta from PID:", $$;
print "\n Note: GNotification is persitant, Even after this application quit, System reboots, Notification will be there until user acknowledge it.";
#All is Well Bye
exit 0;


Here is the stdout looks like,


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 Perl FFI::Platypus Gnome Notification Example
 Found libgio-2.0 in :/usr/lib64/libgio-2.0.so.0.4200.2
 Found libgobject-2.0 in :/usr/lib64/libgobject-2.0.so.0.4200.2
 Found libglib-2.0 in :/usr/lib64/libglib-2.0.so.0.4200.2
 App Name perl.ffi.platypus.gnome.notify.example is valid? 1
 Application Registration ID:1
 Send Welcome notification
 Send Urgent notification
 Notification with Buttons
 Clean Up everything
 Ta Ta from PID:3768
 Note: GNotification is persitant, Even after this application quit, System reboots, Notification will be there until user acknowledge it.

Here is the screen shot of the notifications generated by the above code,


Conclusion. Notify your user with as much as meaningful information. Do not make them to think that your application is not responding and doing something crap !!.

Bye.



Sunday, March 1, 2015

Running Win32 specific perl code in Linux

Hello Readers,

My wife and my son decided to give me a short "me" time. They are out of town for this whole month. I have planned to watch lots of movies and do some more experiments with perl + FFI.

As usual, I will update the experiment results here. Stay tuned.

WINE - Wine is an open source project. It aims to provide a Windows compatibility layer in Linux. So we can run the windows applications with in linux without going through Virtualization or any other tough route.

I must admit that I never really had any success of running useful windows application in my Fedora Linux via WINE. It appears that WINE can properly emulate core APIs but not fully the .NET kind of APIs, Also many guys out there using WINE for running Windows games in Linux Box. Games usually use the raw and core APIs of the OS.

I have a server grade computer with dual boot. One OS is obviously Fedora Linux 21 and other is Windows 7. I hate to login to Windows and my default login is set to Fedora Linux. Most of the time, I will finish my work in Linux OS itself and @Work I force to use Windows 7  laptop anyway. So I will defer my windows releated tasks to @Work laptop.

This week end, I was doing some experiments with perl and I had a situation to Win32 module. I can not do it Linux anyway because Win32 module, As name suggest needs windows OS to run. Win32 module exports a set of Windows OS APIs in to perl world.

In my other dual boot windows os, I have Active State perl v5.21 with all the perl development modules installed. But I don't like to shutdown and boot into Windows OS because of many days I did not login, It will complain about missing patches and older Virus Scanner. (Virus scanner!! another piece of crap, It will slow down the computer like anything and in Linux, We ask what is Virus? :))

Hmm... I have one more choice. In the Linux OS, I have KVM based windows XP virtual machine. I thought to start the Windows XP virtual machine and continue my perl experiments. After I logged into Windows XP virtual machine, I realize that, I do not have my perl development environment setup in it.

Like some people can not sleep in any beds and need their own bed and pillow, I need my development setup else my brain won't let me work. It keep points advantage of my development environment.

By the way, My perl development environment is,

Windows OS: Active Perl 5.20 +Eclipse IDE + EPIC Plugin + PPM for package management + gcc compiler + dmake

Linux OS: System default perl+ Eclipse IDE + EPIC plugin + CPAN for package management + gcc compiler + gmake

So, Windows XP Virtual Machine also not useful for now. I am too lazy to re setup my development environment in the Windows XP Virtual Machine.

Since I have the Dual Boot, I have also mounted my Windows drives (C:, E:) into my Linux via following entries in /etc/fstab file.


1
2
/dev/sda3 /mnt/WinD ntfs-3g rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other 0 0
/dev/sda2 /mnt/WinC ntfs-3g rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions,allow_other 0 0

This allows me to access all Windows OS installed applications in /mnt/WinC. I finally thought to give a try with WINE.

Mission: Run Active Perl 5.20 which is installed in Windows OS in Linux using WINE.

First we need a WINE installed, I have installed long long back (May be since 2003, I have WINE in the Linux system without much usage because I am not a good computer games fan).


1
2
wine --version
wine-1.7.36 (Staging)

Next need to access the Active Perl installation in Windows OS. Using /etc/fstab file, Windows hard disk partition (NTFS) also mounted in Linux under /mnt folder.

Finally run the Active State perl,


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ cd /mnt/WinC/Perl/bin/
$ wine perl -v
fixme:winediag:start_process Wine Staging is a testing version containing experimental patches.
fixme:winediag:start_process Please report bugs at http://bugs.wine-staging.com (instead of winehq.org).
fixme:ole:CoInitializeSecurity ((nil),-1,(nil),(nil),1,2,(nil),0,(nil)) - stub!
err:ole:CoGetClassObject class {0000034b-0000-0000-c000-000000000046} not registered
err:ole:CoGetClassObject no class object {0000034b-0000-0000-c000-000000000046} could be created for context 0x1
fixme:ole:RemUnknown_QueryInterface No interface for iid {00000019-0000-0000-c000-000000000046}

This is perl 5, version 20, subversion 1 (v5.20.1) built for MSWin32-x86-multi-thread-64int
(with 1 registered patch, see perl -V for more detail)

Copyright 1987-2014, Larry Wall

Binary build 2000 [298557] provided by ActiveState http://www.ActiveState.com
Built Oct 15 2014 22:10:49

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.
$ fixme:crypt:ProvStore_release Unimplemented flags 1
fixme:crypt:MemStore_release Unimplemented flags 1
fixme:msvcrt:__clean_type_info_names_internal (0x36e3f8) stub
fixme:msvcrt:__clean_type_info_names_internal (0x10046a20) stub


Hurrah, perl runs smoothly. But WINE spits more debug messages, Its quite distractive. Put off the WINE debug messages with WINEDEBUG environment variable.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
$ export WINEDEBUG=-all
$ wine perl -v

This is perl 5, version 20, subversion 1 (v5.20.1) built for MSWin32-x86-multi-thread-64int
(with 1 registered patch, see perl -V for more detail)

Copyright 1987-2014, Larry Wall

Binary build 2000 [298557] provided by ActiveState http://www.ActiveState.com
Built Oct 15 2014 22:10:49

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

Sweet :) Now, Perl runs as if I am running in Windows. But my main motive is to use the Win32 module, I still need to see WINE + Windows Perl can load the Win32 module.

Before that, I need to setup few environment variables for Windows Perl. Though WINE passes all the environment variables to running application due to OS difference few environment variables like PATH can not passed from Linux to Windows process running in WINE.

Special WINE environement variables needs to be exported via WINE Registry editor. It can be invoked via 'regedit' command OR if you are using KDE / GNOME desktop, You can get it in the start menu.



You can see that I have set the PATH variables with perl specific values. Z: is created by WINE, It is the Linux "/" folder.

Lets run Win32 code,


1
2
3
$ wine perl -e 'use Win32; print Win32::GetOSDisplayName()'

Windows XP Professional Service Pack 3


Awesome. Looks like WINE is emulating Windows XP.

This made me think, why perl can run peroperly under WINE?. Other commercial applications like Adobe Photoshop fails to run under WINE.

This is because Perl is super portable and it is mostly using libC (C runtime) core APIs (and modules will use other APIs, Depends on the Module) and perl as a language do not have may dynamic libs to link with. Basically, Perl is a low dependency language unlike MS Languages (.NETs).

No wonder perl is running in Over 100+ OS !!!!

After a decade, I made use of WINE and I will continue to use with Windows specific perl expriments.

Just now, Got a call from wife and son, Accusing me that, Even they are not in home, I finish blog in late sunday night and its obvious that they are not responsible for me to work in late nights!! True.



Hey, I am also doing experiments with GNotification APIs. Let me update in upcoming blog posts.


Bye Bye folks.