QueueDemo

In program QueueDemo, we save notes in a queue to be played later. (Musicians may be disappointed by (1) the constant note duration, (2) the paucity of notes and (3) the representation of notes by the actual keyboard letters rather than by rows of keys that are easier to play!).

We store the indices of the head and rear of the queue. Procedure Enqueue adds a data item to the queue if it is not already full. Function Dequeue returns the head of the queue (or "0" if the queue is empty) and increments the head index.

program QueueDemo;
  {$APPTYPE CONSOLE}
uses
  SysUtils, Windows;  
const
  NOTE_DURATION = 400;
  MAX = 50;
var
  Notes : array[1..MAX] of char;
  Note : Char;
  HeadIndex, RearIndex, iChoice, ErrorCode, Count : integer;
  strChoice, Tune : string;

function NewNote : char;
var
  Letter : char;
begin
  repeat
    write('Please type the letter of your note. ');
    readln(Letter);
    Letter := UpCase(Letter);
  until Letter in ['A'..'H'];
  result := Letter;
end;

procedure Enqueue(LastNote: Char);
begin
  if RearIndex < MAX then
    begin
      inc(RearIndex);
      Notes[RearIndex] := LastNote;
    end
  else
    writeln('Queue full')
end;

function Dequeue : Char;
begin
  if HeadIndex <= RearIndex then
    begin
      result := Notes[HeadIndex];
      inc(HeadIndex);
    end
  else
    result := '0';//Queue empty
end;

procedure PlayNote(Note : Char);
begin
    write(Note);
    case Note of
      'A' : windows.Beep(440, NOTE_DURATION);
      'B' : windows.Beep(494, NOTE_DURATION);
      'C' : windows.Beep(523, NOTE_DURATION);
      'D' : windows.Beep(587, NOTE_DURATION);
      'E' : windows.Beep(659, NOTE_DURATION);
      'F' : windows.Beep(698, NOTE_DURATION);
      'G' : windows.Beep(784, NOTE_DURATION);
      'H' : windows.Beep(880, NOTE_DURATION);
    end;
end;

procedure Play;
var
  CurrentNote : Char;
begin
  CurrentNote := Dequeue;
  while  CurrentNote <> '0' do
    begin
      PlayNote(CurrentNote);
      CurrentNote := Dequeue;
    end;
end;

procedure Init;
begin
   HeadIndex := 1;
   RearIndex := 0;
end;

begin
  Init;
  repeat
    repeat
      writeln(#13#10'Please type the number of your choice.');
      writeln('1 - Enqueue a note (A to H, where H is A in the next octave)');
      writeln('2 - Enqueue a string of notes (A to H)');
      writeln('3 - Dequeue a note');
      writeln('4 - Hear queue of notes (tune?)');
      writeln('5 - Quit');
      readln(strChoice);
      val (strChoice, iChoice, ErrorCode);
    until ErrorCode = 0;
    case iChoice of
      1 : Enqueue(NewNote);
      2 : begin
            write('Enter the string of notes (A to H)');
            readln(Tune);
            Tune := Uppercase(Tune);
            for Count := 1 to length(tune) do
              Enqueue(tune[Count]);
          end;
      3 : begin
            PlayNote(Notes[HeadIndex]);
            Note := Dequeue;
            if Note <> '0' then
              writeln(' removed')
            else
              writeln('Queue empty');
          end;
      4 : Play;
    end;
  until iChoice = 5;
end. 

In this program the rear index is the actual value of the current rear. Other implementations store the index one greater than the current rear, ready to accept the next item.

With this implementation of a queue, as items are added and removed, the queue moves up the array and will result in wasted memory and the array limit being reached prematurely. This could be improved by (1) moving the queue back down after each dequeue operation, (2) having pointers so that data does not move, or (3) the use of a circular queue as demonstrated in the next section.

Programming - a skill for life!

Demonstrations of queues, circular queues, and linked list queues