I built a simple Morse Code program - in need of optimisation

Here's one I built. It has a couple more optimizations.

// Pin 13 has an LED connected on most Arduino boards.
const byte led = 13;
const int DotLength = 92;

const byte messageString[] PROGMEM = "  Arduinos Rock.  ";

const byte MorseCodeArray[] PROGMEM = {
  0, 0, 0x52, 0, 0, 0, 0, 0x5E, 0x6D, 0x6D, 0, 0, 0x73, 0x61, 0x55, 0x32,             // Special chars
  0x3F, 0x2F, 0x27, 0x23, 0x21, 0x20, 0x30, 0x38, 0x3C, 0x3E, 0x78, 0, 0, 0, 0, 0x4C, // 0-9, :
  0, 5, 0x18, 0x1A, 0xC, 2, 0x12, 0xE, 0x10, 4, 0x17, 0xD, 0x14, 7, 6, 0xF,           // A-O
  0x16, 0x1D, 0xA, 8, 3, 9, 0x11, 0xB, 0x19, 0x1B, 0x1C, 0, 0, 0, 0, 0,               // P-Z
  0, 5, 0x18, 0x1A, 0xC, 2, 0x12, 0xE, 0x10, 4, 0x17, 0xD, 0x14, 7, 6, 0xF,           // a-o
  0x16, 0x1D, 0xA, 8, 3, 9, 0x11, 0xB, 0x19, 0x1B, 0x1C, 0, 0, 0, 0, 0                // p-z
};

void setup() {
  pinMode(led, OUTPUT);
  digitalWrite(led, LOW);
}

void BlinkDot()
{
  digitalWrite(led, HIGH);
  delay(DotLength);
  digitalWrite(led, LOW);
  delay(DotLength);
}

void BlinkDash()
{
  digitalWrite(led, HIGH);
  delay(DotLength * 3);
  digitalWrite(led, LOW);
  delay(DotLength);
}

void EndOfLetter()
{
  delay(DotLength * 2);
}

void EndOfWord()
{
  delay(DotLength * 4);
}

void BlinkLetterCode(byte LetterCode)
{
  if (LetterCode > 1)
  {
    BlinkLetterCode(LetterCode >> 1);
    if (LetterCode & 1)
      BlinkDash();
    else
      BlinkDot();
  }
  else
    EndOfLetter();
}

void loop() {
  int i;
  char ch;

  for (i = 0;; ++i)
  {
    ch = pgm_read_byte(messageString + i);
    if (ch == 0)
      break;
    if (ch == ' ')
      EndOfWord();
    else if (ch > ' ' && ch <= 0x7F)
    {
      ch = pgm_read_byte(MorseCodeArray + ch - 0x20);
      BlinkLetterCode(ch);
    }
  }
}

Basically, each ASCII character letter is encoded into a byte in the MorseCodeArray. The first 1 bit signals the beginning of the data. After that, 0's are dots and 1's are dashes. So A is encoded as 5, which is 00000101 in binary -- the leading zero bits are ignored, the first one bit signals the beginning of the data, and the data bits are the 0 and the 1, which translate into dot dash. B is 0x18 in hex which is 00011000 in binary, which corresponds to dash dot dot dot. And so forth.

The BlinkLetterCode function is a recursive function that decodes the binary byte into dots and dashes. It could easily be coded in a loop, but the data would have to be reversed.

PROGMEM, and the corresponding pgm_read_byte calls put the data into flash instead of RAM.