Tuesday 29 March 2016

HOWTO: Logitech Media Server + BrutefirDRC Plugin in Linux Virtual Machine (VM)

Looking back, early-January was a busy time for me! A number of work responsibilities and then I also had to deal with a computer issue - perhaps THE most annoying computer issue - hard drive failure on my server machine...

Of course important data was backed up so I didn't lose anything (I keep copies of important files in both my workstation computer in the upstairs office as well as the basement server). However, replacing hard drives remains an unfortunate and tiring affair of the modern day do-it-yourself tech user and computer audiophile. It turned out than a 2010 Western Digital 2TB WD20EARS "Caviar Green" was the cause of some file access slowdowns I was experiencing. I've since replaced the drive with a new 6TB Western Digital Red 6TB WD60EFRX. I believe these "Red" drives meant for NAS usage have reasonably good reputations for reliability.

Now the "good" thing about this otherwise unfortunate episode is that as I was tinkering with the server computer, I got to thinking more about the whole "keeping it simple" idea (I wrote about this idea late last year - of course that article was more about the whole concept of simplifying hi-res audio albums). But what about "keeping it simple" on the hardware side?

Over the past few years, I've done more with my computer in the listening room (as per my HTPC build articles - here and here). This has certainly allowed me to explore stuff like starting on the path down digital room correction (here and here), easily access my multichannel library through JRiver and HDMI to the receiver, and use my TEAC UD501 DAC for high-resolution and native DSD playback through USB. That's all of course on top of the video home theater tasks. But in fiddling with all this stuff, I found myself "missing" the simplicity of what I had done for years - just kicking back in the evenings in front of my sound system and streaming beautiful music off my good ol' Logitech Transporter machine which has been my main "go to" player for close to the last decade.
Despite the Transporter having been in the audio "rack" all this time, the reason I had reduced my use of it was because digital room correction sounds so "right" through my computer with JRiver that going back to an uncorrected playback just would not do! This is actually the same reason I haven't been playing much vinyl these days...

Well, no way was I going to let this situation continue :-). I decided that it was time to get Logitech Media Server (LMS) running with digital room correction utilizing the FIR filters made with Acourate. Years ago, I was able to do something like this with the Inguz Audio plugin in Windows, but sadly I have not been able to get this working for awhile using the latest builds of LMS (7.9.x). There was only one "easy" option left, go Linux and get BrutefirDRC plugin working!

Without completely converting to Linux because I have other server functions I needed in Windows,  I was going to have to implement this in my existing Windows Server 2012R2 machine as a "virtual machine" (VM). This HOWTO documents the process; as much as I hope it might help those who want to try this themselves, this blog post will also serve as a reminder to myself in the future should I need to set this up again! :-)

Let's go through this step-by-step... [I do of course expect working knowledge of Linux/Unix for anyone going to give this a try.]

1. Make sure you understand your VM software and how it works... Windows Server 2012 includes a "Hyper-V Manager" for creating VMs, so I just used that. Many other options of course - VMware, Oracle VM VirtualBox... Even more important is which distribution of Linux to get because that determines how software is install. I decided to choose Linux Mint 17.3 (supported to 2017) just to experience another distro and I have heard good reviews. It's based on Debian and Ubuntu so shares the Advanced Packaging Tool system.

As expected, you download the Linux ISO. Boot into it and install the OS in the VM...

For me, a small VM with only 15GB virtual HD was all I needed. 3GB of RAM was also adequate - "Enable Dynamic Memory" optional (my Windows Server machine has 16GB of RAM total so this isn't asking for too much). Use 'Generation 1' VM to have access to hardware 3D acceleration emulation.


2. We now need to make sure the music directories are available to Linux so LMS can access them. Since I have all my music in the Windows Server side, I make sure I turn on sharing on the Windows Server. On the Linux VM side, first make sure Samba filesystem is recognized (CIFS is the cross-platform network file system standard than handles SMB), install the cifs-utils package (of course you'll need to do this as administrator or with the sudo command depending on your Linux distribution):
apt-get install cifs-utils
I now edit /etc/fstab to automatically mount the directories on start-up. Here's my fstab file:
# /etc/fstab: static file system information.
#
# Use 'blkid' to print the universally unique identifier for a
# device; this may be used with UUID= as a more robust way to name devices
# that works even if disks are added and removed. See fstab(5).
#
# <file system> <mount point> <type> <options> <dump> <pass>
# / was on /dev/sda1 during installation
UUID=f30de94f-308c-40d1-9d8e-b8c56e1a3573 / ext4 errors=remount-ro 0 1
# swap was on /dev/sda5 during installation
UUID=80a2430e-7256-45db-8d1a-578c60fc4c0f none swap sw 0 0
/dev/fd0 /media/floppy0 auto rw,user,noauto,exec,utf8 0 0

//192.168.1.80/jeeves_music1   /media/Music cifs rw,user,username=<User>,password=<password> 0 0
//192.168.1.80/jeeves_music2   /media/Music2 cifs rw,user,username=<User>,password=<password> 0 0
//192.168.1.80/jeeves_music3-vids /media/Music3 cifs rw,user,username=<User>,password=<password> 0 0
(192.168.1.80 is the Windows Server machine, with shared Samba directories named "jeeves_music1", "jeeves_music2", and "jeeves_music3" for my music spread across 3 drives. Mount these Samba directories over to /media/Music, /media/Music2, and /media/Music3. <User> and <password> of course represent security measures used.)

You can now reboot and make sure the /media/Music? files are now mounted and you can see the contents of the directories.

3. Now start to install components of the DSP system and make sure SoX and LAME installed for LMS:
apt-get install brutefir
apt-get install sox
apt-get install lame
 4. Get the BrutefirDRC plugin for LMS from SourceForge. Also download the "filter examples" file which could be useful to examine later when writing the filter configurations. Current version of BrutefirDRC plugin I'm using is 4.1 beta.

Make the directory: /var/lib/squeezeboxserver/Plugins. This is where LMS expects to see user installed plugins. Then un-tar the plugin there.
tar -zxvf BrutefirDrc_4.1.beta.tar.gz
You should now see the directory "BrutefirDrc" there.

5. Now let's get those Acourate FIR filters in the right place! Make a couple of directories:
mkdir /etc/squeezeboxserver/BrutefirDrc
mkdir /etc/squeezeboxserver/BrutefirDrc/filters
mkdir /etc/squeezeboxserver/BrutefirDrc/settings
The settings directory will be used by the plugin and we don't need to touch anything in there (not sure if this directory is automatically created so might be optional here). Go into the filters directory just created. Copy over the WAV files created by Acourate to the Linux side. These WAV files need to be split into right and left channels for Brutefir. For every WAV file you want to use (eg. in this sample "cor1s96.wav"), do this with SoX:
sox cor1s96.wav -t raw -c 1 96-l.pcm mixer -l
sox cor1s96.wav -t raw -c 1 96-r.pcm mixer -r
[Note that the mixer function has been deprecated and I'm sure there's an equivalent using the remix function instead. The command lines above are good until sox-14.4.1.]

This will create left and right channels consisting of "raw", single channel, 64-bit audio files named "96-l.pcm" and "96-r.pcm" compatible with Brutefir. These files will be referenced in just a little bit when we create the configuration file. Notice that in this example, I used a 96kHz filter file... I have 44/48/88kHz files as well. The beauty is that the newer plugin versions (from version 4) are smart enough to switch based on the material being played. So here's what my directory looks like with the various samplerates and L/R channels:


6. Time to create the filter settings to be used by Brutefir. This is where you might want to have a look at the samples in the "filter examples" file you may have downloaded earlier with BrutefirDrc. As you can imagine, there are a bunch of potential settings to play with but for the sake of brevity, here's what I used for my room correction based on the .pcm filters created above. (This is the 96kHz version linking the 96kHz 96-l.pcm and 96-r.pcm files saved as "DRC-96000.txt".)
## DEFAULT GENERAL SETTINGS ##

float_bits: 64;                # internal floating point precision
sampling_rate: 96000;        # sampling rate in Hz of audio interfaces. Must match sample rate of filter .pcm if present in config
filter_length: 16384,8;        # length of filters
overflow_warnings: true;    # echo warnings to stderr if overflow occurs
show_progress: false;        # echo filtering progress to stderr
max_dither_table_size: 0;    # maximum size in bytes of precalculated dither
allow_poll_mode: false;        # allow use of input poll mode
modules_path: ".";            # extra path where to find BruteFIR modules
monitor_rate: false;        # monitor sample rate
powersave: true;            # pause filtering when input is zero
lock_memory: false;            # try to lock memory if realtime prio is set
convolver_config: "/etc/squeezeboxserver/BrutefirDrc/settings/wisdom"; # location of convolver config file


coeff "drc_l" {
filename: "/etc/squeezeboxserver/BrutefirDrc/filters/96-l.pcm";
format: "FLOAT64_LE"; # file format
attenuation: 6.75; # attenuation in dB
blocks: -1; # how long in blocks
skip: 0; # how many bytes to skip
shared_mem: false; # allocate in shared memory
};

coeff "drc_r" {
filename: "/etc/squeezeboxserver/BrutefirDrc/filters/96-r.pcm";
format: "FLOAT64_LE"; # file format
attenuation: 6.75; # attenuation in dB
blocks: -1; # how long in blocks
skip: 0; # how many bytes to skip
shared_mem: false; # allocate in shared memory
};

## INPUT DEFAULTS ##

input "l_in","r_in" {
device: "file" {path: "/dev/stdin";}; # module and parameters to get audio
sample: "S24_LE"; # sample format
channels: 2/0,1; # number of open channels / which to use
delay: 0,0; # delay in samples for each channel
maxdelay: -1; # max delay for variable delays
mute: false,false; # mute active on startup for each channel
};

## OUTPUT DEFAULTS ##

output "l_out","r_out" {
device: "file" {path: "/dev/stdout";}; # module and parameters to put audio
sample: "S24_LE"; # sample format
channels: 2/0,1; # number of open channels / which to use
delay: 0,0; # delay in samples for each channel
maxdelay: -1; # max delay for variable delays
mute: false,false; # mute active on startup for each channel
dither: false; # apply dither
};

# Digital room correction
filter "l_drc" {
from_inputs: "l_in"/0.00;
to_outputs: "l_out";
process: -1; # process index to run in (-1 means auto)
coeff: "drc_l";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};

filter "r_drc" {
from_inputs: "r_in"/0.00;
to_outputs: "r_out";
process: -1; # process index to run in (-1 means auto)
coeff: "drc_r";
delay: 0; # predelay, in blocks
crossfade: false; # crossfade when coefficient is changed
};

# filter_attenuation=0.00
Change the sampling_rates setting, also the coeff "drc_l" and coeff "drc_r" block parameters to correspond to the various filter files. Remember to identify the FLOAT64_LE raw file format derived by SoX from the Acourate input .wav filter. Notice I also put an attenuation of 6.75dB. This depends on the filter being used and how I derived at this value was to connect the digital output of my Transporter into the Behringer DEQ2496 and measure the peak level using some loud music like the first track "Billie Jean" (DR5) off Michael Jackson's King Of Pop. With a 6.75dB attenuation, the DSP results in a -0.2dB peak on a poorly "modern" remastered track like this which has tremendous amount of 0dBFS peak limiting. I reckon that if the filter doesn't clip with music like this, there will be no issue with 98.8% of everything else I have, and 100% good for anything that didn't engage in the Loudness War and was actually mastered well. :-)

By the way, for those who insist on clip-free attenuation, Iggy & The Stooges "Your Pretty Face Is Going To Hell" (from the egregiously loud 1997 DR1 remaster of Raw Power) can be used for this purpose. I reckon that any DSP setting that doesn't clip within 10 seconds on Iggy & The Stooges will be good for 99.9999% of all music! For me, the attenuation would have been as much as -11dB and for most music, the output level would have been too low for my liking.

Another thing to consider about the attenuation level is that I could use lower amounts for the higher sample rates like 88kHz and 96kHz. For me, any album with average DR <10 is unworthy of keeping as a high-resolution file (as discussed previously) - no exceptions. Therefore, even an attenuation level of -3dB would probably be completely adequate for clip-free playback for decent quality mastered high-resolution audio.

With these files in place, the filter directory now looks like this (you can ignore that Delay_Test.txt file which was just one of the example config files):


Notice the series of files "DRC-xxxxx.txt"; the xxxxx of course represents the samplerate up to 96000 which allows auto-switching. If you have 176 and 192kHz files, feel free to convert those as well and create DRC-176400.txt and DRC-192000.txt files.

Tip: If at some point you run into what looks like issues with the plugin accessing the settings/filter files, check and possibly chown the files to be owned by squeezeboxserver (sudo chown squeezeboxserver:nogroup *). I remember running into this issue at some point while testing things out early on. Also, I had to delete the BruteFir-created wisdom file in the /etc/squeezeboxserver/BrutefirDrc/settings directory.


7. Install LMS and make sure proper DSP settings are applied to your player device. These days, though there's always the risk of a bad build, I've generally found the Nightly Builds of LMS 7.9.x to be quite stable, so I just grab the latest Debian package (x86_64). Install it, for example:
sudo dpkg -i logitechmediaserver_7.9.0~1453998754_amd64.deb
Now figure out what the IP address of the Linux Virtual Machine:
ip addr show
As usual, point your web browser to the LMS page (192.168.1.125:9000 in my situation). Check out the Settings --> Plugins page and you should see "BruteFIR Room Correction" there:


Click on the Settings to make sure the directories as where we put our filters files above:

Okay, now go into the Players tab and select the player to apply the DSP for - in my case, it's for my Transporter:

I've found the FLAC streaming option works well for me. For some reason, the PCM option isn't engaging brutefir for me. Remember the stream will be 24-bits and potentially 96kHz. Remember also that this is a virtual machine and my Windows Server 2012 machine acts as NAS storage which means there's even more data being transferred across the network rather than through a local drive, so a little data compression with FLAC should be just fine at the expense of more CPU processing. Below "Template" is the filter setting. Remember that the plugin is smart enough to switch samplerate so just select one of the files representing the template (in my example here, I selected the 96kHz version of the "DRC-xxxxx.txt" series).

To improve speed, also make sure to go into the Advanced --> Performance --> Database Memory Config tab and set it to "Maximum" if you're running with at least 2GB RAM.

You can now restart the LMS daemon to get all the settings reloaded/refreshed:
/etc/init.d/logitechmediaserver restart
 8. Now go play some music!

If you crossed your fingers / prayed to a higher power / the stars aligned /etc... you should now be hearing your music through the Squeezebox with room correction DSP applied. If so, congrats! If not, good luck :-).

You can quickly check that Brutefir is running when playing a song with the top command. It should take up a number of CPU cycles of course:

I hope this is helpful for those wanting to get Brutefir running on their machine... I certainly am not a Linux guru so if there are detailed questions, check out the official BrutefirDRC Google Groups forum as well.

Of course, feel free to play with all those other BrutefirDRC features...

Overall the "virtualization" of LMS functions well. I have not noticed any buffer under-runs even with the inexpensive underclocked 3.3GHz AMD A10-5800K CPU on the server. Controls using Android Orange Squeeze or Squeeze Commander remains as fast as when LMS was running off native Windows. The only penalty I have noticed is in the music scanning speed going through the network over SMB/cifs - maybe a 10-20% penalty... Even so, it's not a big deal unless I'm rebuilding the whole music database.

The great thing about using a virtualized machine is also that I can easily copy and import the VM whenever I upgrade or change the server (so long as it's an x64 machine of course). So long as the SMB network directories are the same; even if things change, no big deal, just edit the /etc/fstab and change LMS music directories.

Current issues:
1. As noted in step 7, only the FLAC streaming option is working for me so far.
2. I still have not been able to get 176 and 192kHz music playing properly on my Transporter. Music plays but it sounds as if the sox resampling down to 88 and 96kHz respectively isn't working properly. (The Transporter is only capable of up to 96kHz.)

Anyone with tips on the above, please let me know if I'm missing something in my steps or some customization that's still needed. Otherwise it is running stable for more than a month now...

-----------------------

Aahhhh yes... Back to the "simple life" with streaming Squeezeboxes :-). Speed and stability of Logitech Media Server, high accuracy 64-bit DRC processing with customization for each player in the Squeezebox family I have set up around my house! Very happy...

Have a great week ahead all. And of course hope you're all enjoying the music!

--------

Update - January 2017:
Decided to move over the LMS + BrutefirDRC set-up over to a Ubuntu Desktop 16.04.1 LTS setup. I wanted it a little more optimized with just 1.5GB RAM use for the VM, and 15GB HD was fine. Installed "linux-virtual" package in Ubuntu to load fewer drivers and run more efficiently...

Update - April 2018:
For completeness and future reference. If running Ubuntu Desktop in Windows Server Hyper-V, make sure to install Remote Desktop Virtualization Host in the role services to open up 3D hardware acceleration. Much smoother GUI especially over Remote Desktop and lower CPU utilization.

Update - June 2018:
Recent updates to Linux and Windows Server 2016 required me to make sure SMB versions 2 or 3 be used otherwise network mounted drives timed out. Fix this with editing /etc/samba/smb.conf.

Add the following line under the workgroup = WORKGROUP line:
client min protocol = SMB2
client max protocol = SMB3
Worked for me...

Update - August 2018:
Updated Ubuntu to 18.04.01 LTS - less issue with Samba/CIFS. Also converted to Oracle VirtualBox - much easier, "freer" open source than Microsoft's Hyper-V for my purposes. VirtualBox is also better with being able to resize display of the virtual machine without much fuss. Also, more flexible with network set-up (use "Bridged Adapter" mode to run server inside VM). If you have trouble installing a 64-bit VM, turn off the Hyper-V function in Windows (Server).

Updated to latest "nightly" version of LMS 7.9.2 (1533033975) also.

Misc notes while reinstalling BrutefirDrc and getting it to work:
- You can check the Brutefirdrcwrapper log at: /var/log/squeezeboxserver/brutefir.log for errors.
- Provide the system with all the main samplerates - 44.1/48/88.2/96kHz configs and impulse PCM files. Possibly also 176.4 and 192kHz settings if you have many of these files.
- Permissions often an issue. chmod 755, chown squeezeboxserver:nogroup -R.
- Give it time for the creation of the wisdom file by brutefir.
- Check the link in /etc/squeezeboxserver/BrutefirDrc/settings/filter-xx_xx_xx_xx_xx that it's linking to the correct filter setting like /etc/squeezeboxserver/BrutefirDrc/filters/DRC-96000.txt as in the example filenames above. Sometimes the link is not formed properly and need to select the FLAC/filter setting in the LMS settings tab for BruteFIR a couple times.
- With each CPU hardware change, make sure to delete /etc/squeezeboxserver/BrutefirDrc/settings/wisdom and let the program create a new wisdom file which is customized to the CPU architecture for speed enhancement
- Feel free to install WavPack 5 for DSD compression and playback.

Finally, at this point Linux is stable enough for this simple purpose that I think it's worth not updating for awhile :-).


Update - May 2020:
Updated to latest Ubuntu 20.04 LTS. Using Oracle VirtualBox to share host "MusicX" directories instead of sharing through CIFS/SMB which speeds things up. Need to install the Guest Additions as per instructions.

1. Need to activate the directory share feature on VirtualBox settings pointing to /mnt/MusicX directories inside the virtual machine. Use "read-only", "automatic mount", and "permanent".

2. sudo apt-get install gcc make (maybe another one or two which Guest Additions will say)

3. Mount the "Guest Additions" virtual CD-ROM in the host.

4. Go to the mount location like cd /media/<username>/<guest additions>

5. sudo rcvboxadd setup

6. sudo sh ./VBoxLinuxAdditions.run

7. mkdir /mnt/MusicX directories as mount points. Edit /etc/fstab to add following lines as appropriate for your setup for the shared folder mount:
     Music1   /mnt/Music1   vboxsf   defaults  0   0
     Music2   /mnt/Music2   vboxsf   defaults  0   0
     Music3   /mnt/Music3   vboxsf   defaults  0   0

8. Reboot Linux and should be able to access /mnt/MusicX shared folders.

Should be able to add the music in the various directories and set up scans in LMS as usual...

12 comments:

  1. I am currently implementing something potentially similarly simple for my desktop system. Since it is a home office system I use the desktop computer as my source for sreaming. The next item in the line is then the ODAC usb DAC. Next after that is an Emotiva Control Freak volume control, plus some additional 12 db attenuators to play it safe, and that into a refurbished QUAD 405-2 amplifier driving a pair of Harbeth P3ESR mini monitors. It is a very simple system if you do not use analogue sources. Given the proximity of the desk to the speakers there is a bit of bass colouration (absent when I play the same stunning speakers in a more favourable environment). Unfortunately I have no tone controls in the amplification stage to tame the bass, so I installed Equalizer APO on my computer to rectify this. That has more options than I care for, so I still have some way to go, even of it is already clear that using only the most basic functionality of the software the sound is already cleaner. What I am really planning is to use REW to measure in room response, and apply an REW correction curve to the Equalizer APO. I too cannot really imagine audio without room correction anymore. In principle the combination of REW and Equalizer APO should do the trick, but I cannot say that it is easy for computer dummies like me.

    ReplyDelete
    Replies
    1. Cool Willem! That's quite the audio chain you got going... Good luck and hopefully you get everything working well.

      Delete
  2. An even simpler setup would be to use the analogue output of a Chromecast. With that, you avoid the computer and the external DAC. What you cannot do then, of course, is do any equalization. Unless perhaps someone writes an app for that - would that be possible?

    ReplyDelete
    Replies
    1. One thing I have not tried with Chromecast Audio was streaming from JRiver with DSP performed through the DLNA. This will give room correction options and covolution.

      I wonder has anyone tried this...

      Delete
  3. "Back to the "simple life" with streaming Squeezeboxes :-). Speed and stability of Logitech Media Server, high accuracy 64-bit DRC processing with customization for each player in the Squeezebox family I have set up around my house! Very happy..."

    Can you run several instances of BruteFIR simultaneously so that you get room correction individually in all rooms at the same time?

    ReplyDelete
    Replies
    1. Hmmm, have not tried...

      Anyone else know? Take up CPU processing but I imagine doable.

      Delete
  4. Its easy with a simple chinese Pipo X9 PC with Windows10, a simple chinese DAC (Douk audio 384k/32-bit) and JRiver (total 200 euro's); works very well and a superior quality.
    I did run DRC-designer, after initial measuring with REW with Behringer ECM8000 mic, on the PipoX9 with JRiver with no problems; All this can be done on a simple touchscreen, 9inch Windows mini PC; no noisy cooling fans, etc. A good replacement for a HTPC as it also plays video through HDMI, Netflix, etc.
    However I did not get good results in my main listening room with digital room correction ;so I went for the multi-sub approach and I am happy now with a "no so flat" response with three Rel subs (REL-Stadium) and a subjective "relaxt" bass-reponse added to my B&W801 speakers
    In my basement I use a Logitech Squeezebox touch and in my bedroom a cheap O2-Joggler (30euro) with Logitech software. All connected to a NAS (Synology) with LMS but also acting as a general musicserver (all Flac)

    ReplyDelete
    Replies
    1. Hi Ik Ja. Just Googled this Pipo X9 machine. Not the prettiest but like you say, should do the job :-).

      Glad to hear you got this going!

      Delete
    2. Pipo X9 looks quite interesting. Nice form factor. I'd like to run WMC on it for terrestrial TV. It does seem the alternatives then are either to install Windows 8.1 with WMC over the W10, or try some hack on W10, where the latter seems more uncertain. It also seems the X9 has had quite a few quality problems, such as being dead for days before turning on again, etc, as seen here: http://freaktab.com/forum/tv-player-support/intel-based-tv-players/541961-pipo-x9-owners-here

      Delete
  5. I am using the X9 since october 2015 ; I did the upgrade to windows10, installed drivers for DAC, installed JRiver and thats it. Keep it simple and you have a very stable system. I use it as a replacement for my Logitech Squeezebox Touch because of the , better, JRiver-software and the very handy 10 inch touchscreen of the Pipo X9; conveniënt and a very good quality on my simple systeem (X9 with JRiver, Synology NAS and Douk-Audio DSD1796 XMOS Asynchronous 384K/32bit USB DAC as a source with direct feed (no pre-amp just a simple switchboard and pot-meter for level-adjustments) to Hypex UcD-400 DIY class-D mono-amps's and B&W801N speakers,and 3 REL subwoofers.
    no problems for me so far. People often start messing with things; that is OK but often introduces problems.

    ReplyDelete
  6. Hello. Nice article. I would like to ask you about possibility to use LMS with BruteFir DRC convoler not only for music played from file share on LAN but also for music streamed from Tidal via existing LMS plugin. I would like to listen Tidal stream via LMS with applied FIR filters in BruteFir. Is it possible? Thanks in advance Regards. Marek

    ReplyDelete
  7. @kryton: yes this is possible. even in 2020 may ;)

    ReplyDelete