From lalbers@HRZ.Uni-Bielefeld.DE Thu Aug 14 09:50:35 1997
Return-Path: <lalbers@HRZ.Uni-Bielefeld.DE>
Received: from trc.amoco.com by attcmail.trc.amoco.com (SMI-8.6/SMI-SVR4)
	id JAA28191; Thu, 14 Aug 1997 09:50:33 -0500
From: lalbers@HRZ.Uni-Bielefeld.DE
Received: from corpmx02 (corpmx02.trc.amoco.com) by trc.amoco.com (4.1/SMI-4.1)
	id AA21139; Thu, 14 Aug 97 09:50:39 CDT
Received: from virlmx02 by corpmx02 (SMI-8.6/SMI-4.0)
	id JAA10620; Thu, 14 Aug 1997 09:40:16 -0500
Received: from interlock.amoco.com by virlmx02 (SMI-8.6/SMI-SVR4)
	id JAA15664; Thu, 14 Aug 1997 09:48:23 -0500
Received: from kana.Stanford.EDU by portal.amoco.com with SMTP id AA28550
  (InterLock SMTP Gateway 3.0 for <jdellinger@trc.amoco.com>);
  Thu, 14 Aug 1997 09:50:28 -0500
Received: from hermes.hrz.uni-bielefeld.de (hermes.hrz.uni-bielefeld.de [129.70.4.55]) by kana.Stanford.EDU (8.8.6/8.7.1) with ESMTP id HAA15920 for <joe@sep.stanford.edu>; Thu, 14 Aug 1997 07:50:24 -0700 (PDT)
Received: from tina.hrz.uni-bielefeld.de by hermes.hrz.uni-bielefeld.de with ESMTP
	(1.37.109.17/16.2) id AA214700380; Thu, 14 Aug 1997 16:53:01 +0200
Received: by tina.hrz.uni-bielefeld.de
	(1.40.112.12/16.2) id AA255710219; Thu, 14 Aug 1997 16:50:19 +0200
Date: Thu, 14 Aug 1997 16:50:19 +0200
Message-Id: <199708141450.AA255710219@tina.hrz.uni-bielefeld.de>
Subject: A module for your morse Program.
Apparently-To: joe@sep.stanford.edu
Content-Length: 6583
Status: RO

Dear Joe

I use your morse program, thanks a lot for your work!

I use a Linux machine which is connected to a keyboard. So I wrote
a small (and bad) module for Linux, which uses the /dev/sequencer
device of Linux OSS sound driver. It is quite uncomfortible. It
destroys the possibility to freely choose the morse pitch and it
doesn't work correct when using "morse -i". (Don't ask me what else
goes wrong)

Anyway, I thought, I should send it to you...

Regards, Leif

(leif.albers@post.uni-bielefeld.de)

     

/* 
 * beepSeq.c for morse (!!BAD ALPHA CODE!!)
 */

/*
 * beep for Linux /dev/sequencer device
 *  up to now without any initialization, i.e. choose your own instrument
 *  by hand. Will probably not work without external midi device (such as
 *  a keyboard.
 *
 * (beepSun.c might work if you have a sound card installed and /dev/audio)
 *
 * Writing this object file I took no care about what the data I send
 * really means. I only watched the output of /dev/sequencer --- the
 * rest was only vague information from the soundcard.h file of the
 * OSS sound driver. This means, I have no Idea what the data
 * I send to /dev/sequencer truely means --- exept that it works for
 * me. (For a short description about what I do (better: what I believe
 * I do) see below.
 *
 * IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT IMPORTANT
 *   If you use this output, the pitch selection mechanisms of
 *   the main program do not work! You are tied to the default
 *   frequencies of 800, 602 and 2000 Hz. If you change them, you
 *   need to change them in this file AND in morse.c
 *   Also the sequencer device is more unprecise. The smallest
 *   time unit is a 1/100 second and a BeepWait() call takes
 *   approximately 3 milliseconds (because you close and reopen
 *   a device file). You might want to use -DDONT_WAIT in the
 *   makefile. Which destroys the pretty output.
 *
 * Leif Albers 8/97
 * (leif.albers@post.uni-bielefeld.de)
 */

/*
 * First /dev/midi. If I want to send a beep to /dev/midi I
 * send 2 signals, each 3 bytes long (HEX):
 *	xx kk vv
 * where
 *	xx  is the signal type (0x90 for key down, 0x80 for key up)
 *      kk  is the keycode measured in halftones, where the note
 *	    "a" is 0x45 (440Hz for an 8' instrument)
 *	vv  is the velocity (between 1 and 100) --- for some reason
 *          on "key up" it has the value 64
 *
 * If I send data to /dev/sequencer I need to connect each data byte
 * with a time stamp. The time is measured in the number centiseconds
 * since the time /dev/sequencer was opened. Each time stamp is stored
 * as a 24 bit unsigned. For some reason this block (first 24 Bit time
 * then 8 bit code) is preceeded by a 0x02 byte and followed by a
 * 0x05 0x00 0x00 byte triplet. This gives us (hex)
 *	02 tt tt tt cc 05 00 00
 * (where cc is the code and tt are the bytes of the time stamp.) Thereby
 * the bytes of the time stamp are sent the least significant bytes first.
 *
 * Please note that in the program I use 16 bit blocks Instead of bytes).
 * Now, when C writes a 16 bit Block (unsigned short) to a file, it
 * exchanges the order of the contained bytes. Take this into account if
 * you try to understand my code. (The same is true if you watch the
 * output of /dev/sequencer using hexdump --- which is in fact the reason
 * for my strange programming.) I apologize for this misprogramming...
 */

#include <stdio.h>


/*
** Data for to /dev/sequencer
*/

/* I know the meaning of: */
#define KEY_DOWN	0x90
#define KEY_UP		0x80
/* I don't know (or vaguely guess): */
#define FIXED_BYTE_02	0x02	/* Probably means "time value absolute"	*/
#define FIXED_BYTE_05	0x05	/* no idea --- maybe "use MPU"?		*/
#define FIXED_BYTE_40	0x40	/* last data byte for "key up"		*/

#define SEQ_DEVICE	"/dev/sequencer"
FILE * device;

/*
** The device takes care about the time all by itself --- I only
** need to take care about storing it.
*/
unsigned long seq_time;



int BeepInit()
{
  seq_time=0;
  return ( (device = fopen(SEQ_DEVICE,"w")) == NULL) ? -1 : 0;
}


int putseq( int duration,	/* in cs */
	    int velocity,	/* [1,100] */
	    int tone )		/* Midi key played */
{
# define BUFFER_SIZE 24
  unsigned short buffer[BUFFER_SIZE];
  unsigned long buffer_filled=0;

  void dump_time()
  {
    buffer[buffer_filled++] = ((seq_time & 0x000000FF) << 8) | FIXED_BYTE_02;
    buffer[buffer_filled++] =  (seq_time & 0x00FFFF00) >> 8;
  }

  /* Key Down */
  dump_time();
  buffer[buffer_filled++] = (KEY_DOWN      << 8) | FIXED_BYTE_05;
  buffer[buffer_filled++] = 0x0000;
  dump_time();
  buffer[buffer_filled++] = (tone          << 8) | FIXED_BYTE_05;
  buffer[buffer_filled++] = 0x0000;
  dump_time();
  buffer[buffer_filled++] = (velocity      << 8) | FIXED_BYTE_05;
  buffer[buffer_filled++] = 0x0000;
  
  /* increase time */
  seq_time += duration;
  
  /* Key Up */
  dump_time();
  buffer[buffer_filled++] = (KEY_UP        << 8) | FIXED_BYTE_05;
  buffer[buffer_filled++] = 0x0000;
  dump_time();
  buffer[buffer_filled++] = (tone          << 8) | FIXED_BYTE_05;
  buffer[buffer_filled++] = 0x0000;
  dump_time();
  buffer[buffer_filled++] = (FIXED_BYTE_40 << 8) | FIXED_BYTE_05;
  buffer[buffer_filled++] = 0x0000;

  return ( fwrite( (void *) buffer,
		   sizeof( unsigned short ),
		   BUFFER_SIZE,
		   device )	< 0 )  ? -1 : 0;
}



int Beep(int time,	/* in ms */
	 int volume,	/* [0..100] */
	 int pitch)	/* in Hz */
{
  /*
  ** first, time and pitch need to be converted --- time to
  ** cs and pitch to an absolute note where 0x45 is a' and
  ** +-n are n halftones up or down. Since this is a useless
  ** calculation I choose default pitches. Please note, that
  ** precise frequency of a note depends on how the instrument
  ** is tuned.
  */
  time = (time+5) / 10;
# define ERROR_PITCH	2000 /* Hz */
# define STD1_PITCH	800  /* Hz */
# define STD2_PITCH	602  /* Hz */
# define ERROR_NOTE	0x5F /* note value h''' about 2000Hz */
# define STD1_NOTE	0x4F /* note value g''  about 800Hz */
# define STD2_NOTE	0x4A /* note value d''  about 600Hz */
  switch( pitch )
    {
    case ERROR_PITCH:
      return putseq( time, volume, ERROR_NOTE );
      break;
    case STD2_PITCH:
      return putseq( time, volume, STD2_NOTE );
      break;
    default:
      return putseq( time, volume, STD1_NOTE );
    }
}


int BeepCleanup()
{
  return (fclose(device) < 0) ? -1 : 0;
}


int BeepWait()
{
  int bool = 0;
  
# ifndef DONT_WAIT
  bool = BeepCleanup();
  bool ||= BeepInit(); /* note the switched logic! "or" here means "and" */
# endif
  return bool;
}

int BeepResume()
{
  return 0;
}


