Spoken like a 1980s chip

In the beginning

In the beginning there was light. Of course there was, but a bang must have followed shortly after. It is not unexpected that the communication between organisms, surrounded by a fluid whether it is air or water, is primarily acoustic rather than visual. While vision remains the king of senses and chemical signals are ubiquitous, interaction using a oscillating pressure producer and a corresponding sensor remains the best compromise to create a versatile rich, abstracted, linear data transfer not requiring line of sight. or any other complex infrastructure apart from a medium that envelops the organism. Thus, speech. I recall the early days of my youth my ZXSpectrum had a Currah Microspeech module which, with only a 2K ROM, was able to produce an infinite number of raspy, but mostly recognisable words. Flash-forwards to today, we have far more powerful utilities producing sounds almost indistinguishable from another human. and Perl allows access to these speech engines. These are powerful, non-trivial utilities, with superior abilities to change intonnation, speed and other forms of expressive audio manipulations. For those interested polease explore PerlSpeak, Festival, e-Speak. Perl is certainly not short of vocalising options.

Pure Perl Implementation

As an old simpleton, however, I can not drag myself away from the genius of the guys who with such limited resources managed so much, into the modern world were memory and processor power limitations are of no real issue. The SP0256-AL2 is the centre of this remarkable primitive utility, and I took it myself to explore how this worked, to transform it into a simple module that can be imported into any Perl program, with no dependencies apart from a means to transfer data to a speaker. There indeed many attempts to emulate this little chip, though I have not come across any that specifically use Perl, I do find resources including this one from Greg Kennedy that allow translation to the allophones used here.

Re-inventing the wheel?

Why do things again that far cleverer people have already done, with far more advanced methods? For several reasons. It helps me learn how things are done. Old methods are not going to be as good as new ones, but use far fewer resources, and this would allow quite a lightweight model for speech synthesis that could be embedded in simple applications and games. This would not require any installation of any heavy weight back-ends, polluting the system with more and more infrequently used libraries. So the "plan" is 1) produce a stand-alone speech synthesis module, 2) progressively make the module more accurate and more recognisable 3) eventually have something anyone can use for fun or for real-life needs.

Now I did make a Piano-like monophonic player (Enable the sound in the embedded video sample to hear), based on a memory of a similar utility I saw many years ago. Most web examples use /dev/dsp for audio transfer to the output device, but this virtual interface no longer exists. A pipe to padsp does allow the emulation of /dev/dsp, and this is what I have used for Linux OS; Win32::Sound has a Windows equivalent of a sink for the raw audio data, as yet to be figured out. Thus we have a beginning of a module:-

SP0256.webm

Emulation

The classic method for emulation of this chip appears (as far as I can tell) to be to record the sounds output from the chip, sampling at much higher frequencies than is output (effectively adding a high pass filter). This results in errors and distortions. Such converted data is available as WAV files, and do not have any of the analog filtering that is performed on the original chip, this is actually much lower in quality that the original. But borrowing this data from various sources enables some semblance of a speech synthesiser, and my experimental modulino represents an early attempt at using unprocessed wave forms. But these wave forms are not only inaccurate and noisy compared to the sounds that came from my 40 year old ZX Spectrum, they take significantly more memory. The unpacked data in a script took 1/2 MB and packed into a Storable file, still take just under 100kb. Can't see my Speccy being too impressed.

Missing the point

BUT this simple way belies the cleverness of the original chip mode of operation. To understand how this is managed in 2kb of ROM one has to explore the disassembly of this ingenious device. Unlike modern speech synthesisers with banks of pre recorded audio allophones, the SP0256 actually appears to have built the output waveform on the fly algorythmically, much the same way as piano.pl generates the raw tone data for each of 96 notes. I do need to pore through this code not that I am familiar with the ancient microprocessor (or assembly for that matter) to see how this actually works. It should be entirely possible to create an ultra-lightweight module capable of generating recognisable speech in Pure Perl without any external speech libraries.

Casting Perls before Splines

As I sit pondering my peas at the dinner table, my thoughts are unnaturally drawn to the similarity between these pulses and Perl. A famous poet once said that "For a hungry man, green peas are more shiny than gleaming pearls". From these green orbs on my plate, the mind drifts to a recent virtual conversation regarding logos, branding, rebirth and innovation in Perl. One wonders whether such heated debates are important, relevant and what it might mean for Perl in the future. The Camel (from the O'Reilly Book on Perl) has long been the image associated with the language, along with the Onion (Origin perhaps from Larry Walls' "state of the onion" presentation). Personally it is not something that I feel passionately about. "Perl, with any other logo would be just as quirky" as Will Shakespeare is reported to have said. But The Camel is the popular, recognisable standard "logo" with some, as yet to be tested, copyright and trademark "issues"

Any way I took it myself to analyse the situation and have finally come to the conclusion that we may be looking at the "problem" the wrong way. Perhaps we are looking at the bigger picture when we should seeing the picture bigger. Maybe, just maybe, that picture of a camel doesn't symbolise Perl, but in fact IS Perl...Perl code, that is. I know it is possible to make pictures that aren't valid perl code. But perhaps over the decades of use we have come to accept an illusion as a reality. When one gives such an illusion a "True" value, one also blurs the distinction between the Virtual Image and a Real Image.. You see a Virtual Image is an image that APPEARS to represent something, but only a Real Image can be projected.

logo.png

So lets examine this image in cruder detail. What immediately pops out to the casual observer, is the silhouette clearly is a two line regular expression:

s/A\
/rl /g

Now why on earth does this snippet appear in the camel in the classic book of Perl? Surely this can not possibly be by chance. Some predestination HAS to be involved. It is at this point, four aforementioned peas slipped off my spoon on to the floor. I don't know if any of the readers who are male and married, have had this experience before, but it was with enormous relief that I saw, glancing up, that this misdemeanor was missed by Mrs Saif.

But surely a sign...the rows of peas...and a regular expression..it can ONLY mean one thing.

$Logo="PEA\n" x 4;   # 4 rows of PEAs
$Logo=~              # Apply the code in the camel
s/A\
/rL /g;
print $Logo;         # print result

#result:- "PErL PErL PErL PErL ";

The rows of "PEA"s get turned into a string of "PErL "s. It seems obvious to me that while we look in vain for the answer to our problems, it is the answer that finds us, the illusive emerging from illusions. A famous admiral said, putting his telescope to his blind eye "I see no ships of the desert". Of course he didn't. He saw Perl code.

Death: A Terminal Experience

A program being executed, self terminating on encountering an non-viable condition is a typical scenario in Perl programs. The death sentence can deliver information about the departed application to the user as justification and demand appropriate resolution for the subsequent reincarnation.

Now I know my code fails more often than it succeeds, and it is for this reason I am planning an alternative wake for the programmed parting of my future terminal applications. As a once-in-a-run-time event, death might be more elaborately delivered, something to be celebrated. The last words of a dying application softens the developers ensuing grief, while encouraging resuscitation with an appropriately delivered injection of code.

Imagine my code being transformed from:-

do_something_risky() or die "you evil monster $!";

into

get_away_with_it() or deathSentence($!)

producing something like this on the terminal:-

death.png

I know such distraction wastes time, there are probably many more error trapping and diagnostic tools available. These may be absorbed over time...I am not really an expert. But I am collecting a series of reasonably uncontroversial, hopefully humorous "epitaphs"...

Integrated Inconsistencies.

I will get it wrong. I will start off by saying that, not just because I am married and this sentiment has been conjugally programmed in me for years, but because doing things "my way" will not suit everybody. We approach life, programming, drawing from different perspectives, different analogies, and one method however disagreeable to one person, may be perfectly logical to another. Even our own actions and analysis show conflicts. Take a cup of tea. I drink from the top of the cup, but measure from the bottom. Take character position in programming code...we measure lines from the top, then character on that line. But when we write, we write one line at a time, populating columns in a line before going to the next line.

The same applies to drawing onto a screen. The reason I want to draw on a screen is because I want to be able to draw charts...following the example of Descartes, one plots a point on X,Y coordinates with the origin on the bottom left hand corner. x comes before y. The same screen is drawn from top to bottom, and the print coordinates are described as row, column. with the origin at top left. Then examine what happens if I were to draw an SVG graph according to the Perl Weekly Challenge 165 by Ryan Thompson. How many people realised that the SVG coordinate system the x,y coordinates are not the same as Cartesian coordinates? You did? Well done!...but I dare say plenty of people didn't.

I wrote Term::Graille, not because Term::Drawille was not good enough, but out of sheer indignation. You see, using Braille characters to draw "Pseudo pixel" graphics on the console would be simple but while I might desire a y-axis that increases as we go up as in charts, the dots in braille characters are confusingly numbered and bit 0 is the top of the character.

Drawing lines requires clever calculations. So I then took over Algorithm::Line::Bresenham, and found the original code appeared to take the y-coordinate before the x-coordinate...blasphemy, even though it made no difference to the actual results (it works both ways equally). You will (or perhaps will not) be pleased to know that x comes before y in the newer extended versions. I even inverted the textAt() character coordinate system in Graille; printing to canvas requires the coordinate system to have Cartesian origins, as text in charts often have to be placed next to the plot positions they target.

Graille Incorporates Turtle-like graphics and line drawing primitives, and in this case using Cartesian coordinates makes perfect sense. Mapping is simple and up and north are positive directions. It appears possible that keeping consistent axes should be acceptable for most needs.

Now that is fine if the data is sourced internally; often however, the data is not. Using external data relies on external paradigms, and one has to accommodate the logic of another representation. Images are read as raster from top down, y=0 is the top line. So plotting on Graille requires the image to be read in and then inverted to look right way up.

 for (my $x =0;$x<$canvas->{width};$x++){
  for (my $y=0;$y<$canvas->{height};$y++){
     $canvas->set($x,$y) # inverting image as the pixels are read
        if $image->GetPixel("x"=>$x,"y"=>$canvas->{height}-$y);
    }
 }

Then there is other bitmap data, font data or sprite graphics again represented top down, left to right. Conversion into blittable blocks requires this consideration. It is at this point I wonder if it is me that is going mad and whether I should stop trying to conflict with established paradigms. Then I realise that in a heterogeneous world conflict is inevitable, diversity is desirable, and confusion a natural and consistent consequence.

animate.gif

fontdemo.gif

I continue updating Term:: Graille, extending drawille, integrating Turtle Graphics (as in the original asciimoo's version, but being in Perl, considerably more elegantly), Coloured lines, Image importing, Animations, 8x8 bitmap fonts, Heterogenous canvas etc, adopting a mainly Cartesian Coordinates for as much as possible. Maybe you think I am doing this completely wrong, but hey, I knew that all along. Version 0.07 coming soon!

The benefits of change, from an amateur's objective perspective.

As a bystander in the evolution of Object-Oriented Programming in Perl, and someone who is really only just starting to get the hang of Perl modules and packages (still not any good at it), I get really quite overwhelmed by ideologies. There is considerable debate about the right way to program things, the right style, the right direction that Perl should go. It is Vim vs Emacs, Atari ST vs Amiga, Mods vs Punks. Really one needs a language to do what one needs it to do, simply, quickly and consistently. For an amateur, Perl has been able to do exactly that for me. I code rubbishly, but hey, who's looking?

But when you look at the clever people in the Perl community, you wonder. You wonder whether you are missing out by not being engaged in the evolutionary process. It is bewildering. I confess I understand a mere fraction of the terms, the rationale, the higher order coding discussions. I have read about Corinna, marvelled at Moose's capabilities, gazed admiringly at Leonerd's prowess, but do not dip my coding toes into the water. You see, I cant swim.

But every body is like, "the water is warm and safe", and "c'mon, Saif, there are no trolls here!".

Ok, ok, let's start in the shallow end. I once had a plan for a collection of "PerlayStation Console Games" (you see what I did there?). Arcade Games for the terminal written in Perl. I could resurrect that while learning "proper" OOP...POOP! But I still have to figure out Slots, Roles, lvalue, (*gasps for air*).

Let's have a plan. Breathe. The way one might develop Perl modules, is first write code without modules that works, sort of like a feasibility test. Then, perhaps separate parts that can go into a module. That module is reused in other projects, and in doing so is tweaked to allow the extended capability. A successful module can be used portably across projects. Then the same program is developed using classes in other OOP paradigms, say Corinna, then perhaps Moo,etc.

Pong was developed, a game with Sprites. The sprites contained position and motion data and the info required to draw the sprite, all contained in a hashRef, which could be passed to subroutines for processing. e.g my $sprite={x=>10....};. This was a deliberate precursor for later conversion into a blessed object e.g. my $sprite=Sprite->new(x=>10,...);, all in all a seemingly painless transformation. The sprite modules that were created from that were initially classic Packages, then eventually as classes using Object::Pad. If I can figure it out I will also use Moo. For the moment the code versions remain monolithic until we have tested it/extended it enough.

Pong

Then we measure. Ease of use, readability, code length, performance and other parameters, trying to OBJECTIVELY determine whether to dive in and enjoy the waters, or just stick to shore where it is safe.