diff --git a/src/conio/cterm.c b/src/conio/cterm.c
index d102246e19a96523ab9918d1f174e2884beb24b0..1506a54ac1e954492689093be79401632182e983 100644
--- a/src/conio/cterm.c
+++ b/src/conio/cterm.c
@@ -47,10 +47,276 @@ struct cterminal cterm;
 /* const int tabs[11]={1,8,16,24,32,40,48,56,64,72,80}; */
 const int cterm_tabs[11]={9,17,25,33,41,49,57,65,73,80,80.1};
 
+const char *octave="C#D#EF#G#A#B";
+
+/* Characters allowed in music strings... if one that is NOT in here is
+ * found, CTerm leaves music capture mode and tosses the buffer away */
+const char musicchars="abcdefgABCDEFGpPnN0123456789.-+#oOtOlLmMsS<> ";
+const uint note_frequency[]={	/* Hz*1000 */
+/* Octave 0 (Note 1) */
+	 65406
+	,69296
+	,73416
+	,77782
+	,82407
+	,87307
+	,92499
+	,97999
+	,103820
+	,110000
+	,116540
+	,123470
+/* Octave 1 */
+	,130810
+	,138590
+	,146830
+	,155560
+	,164810
+	,174610
+	,185000
+	,196000
+	,207650
+	,220000
+	,233080
+	,246940
+/* Octave 2 */
+	,261620
+	,277180
+	,293660
+	,311130
+	,329630
+	,349230
+	,369990
+	,392000
+	,415300
+	,440000
+	,466160
+	,493880
+/* Octave 3 */
+	,523250
+	,554370
+	,587330
+	,622250
+	,659260
+	,698460
+	,739990
+	,783990
+	,830610
+	,880000
+	,932330
+	,987770
+/* Octave 4 */
+	,1046500
+	,1108700
+	,1174700
+	,1244500
+	,1318500
+	,1396900
+	,1480000
+	,1568000
+	,1661200
+	,1760000
+	,1864600
+	,1975500
+/* Octave 5 */
+	,2093000
+	,2217500
+	,2349300
+	,2489000
+	,2637000
+	,2793800
+	,2959900
+	,3136000
+	,3322400
+	,3520000
+	,3729300
+	,3951100
+/* Octave 6 */
+	,4186000
+	,4435000
+	,4698600
+	,4978000
+	,5274000
+	,5587000
+	,5920000
+	,6272000
+	,6644000
+	,7040000
+	,7458600
+	,7902200
+};
+void playnote(int notenum, int notelen, int dotted)
+{
+	/* Tempo is quarter notes per minute */
+	int duration;
+	int pauselen;
+
+	if(dotted)
+		duration=360000/cterm.tempo;
+	else
+		duration=240000/cterm.tempo;
+	duration/=notelen;
+	switch(cterm.noteshape) {
+		case CTERM_MUSIC_STACATTO:
+			pauselen=duration/4;
+			break;
+		case CTERM_MUSIC_LEGATO:
+			pauselen=0;
+			break;
+		case CTERM_MUSIC_NORMAL:
+		default:
+			pauselen=duration/8;
+			break;
+	}
+	duration-=pauselen;
+	BEEP(note_frequency[notenum]/1000,duration);
+	SLEEP(pauselen);
+}
+
 void play_music(void)
 {
-	/* ToDo Music code parsing stuff */
+	int		i;
+	char	*p;
+	char	*out;
+	int		offset=0;
+	char	note;
+	int		notelen;
+	char	numbuf[10];
+	int		dotted=0;
+	int		notenum;
+
+	for(p=cterm.musicbuf;*p;p++) {
+		notenum=0;
+		switch(toupper(*p)) {
+			case 'M':
+				p++;
+				switch(toupper(*p)) {
+					case 'F':
+						cterm.musicfore=TRUE;
+						break;
+					case 'B':
+						cterm.musicfore=FALSE;
+						break;
+					case 'N':
+						cterm.noteshape=CTERM_MUSIC_NORMAL;
+						break;
+					case 'L':
+						cterm.noteshape=CTERM_MUSIC_LEGATO;
+						break;
+					case 'S':
+						cterm.noteshape=CTERM_MUSIC_STACATTO;
+						break;
+					default:
+						p--;
+				}
+				break;
+			case 'T':						/* Tempo */
+				out=numbuf;
+				while(isdigit(*(p+1)))
+					*(out++)=*(++p);
+				*out=0;
+				cterm.tempo=atoi(numbuf);
+				if(cterm.tempo>255)
+					cterm.tempo=255;
+				if(cterm.tempo<32)
+					cterm.tempo=32;
+				i=1;
+				break;
+			case 'O':						/* Octave */
+				out=numbuf;
+				while(isdigit(*(p+1)))
+					*(out++)=*(++p);
+				*out=0;
+				cterm.octave=atoi(numbuf);
+				if(cterm.octave>6)
+					cterm.octave=6;
+				i=1;
+				break;
+			case 'N':						/* Note by number */
+				if(isdigit(*(p+1))) {
+					out=numbuf;
+					while(isdigit(*(p+1))) {
+						*(out++)=*(p+1);
+						p++;
+					}
+					*out=0;
+					notenum=atoi(numbuf);
+					i=1;
+				}
+				if(notenum==0) {
+					notenum=-1;
+					offset=1;
+				}
+				/* Fall-through */
+			case 'A':						/* Notes in current octave by letter */
+			case 'B':
+			case 'C':
+			case 'D':
+			case 'E':
+			case 'F':
+			case 'G':
+			case 'P':
+				note=toupper(*p);
+				notelen=cterm.notelen;
+				offset=0;
+				dotted=0;
+				i=1;
+				while(i) {
+					i=0;
+					if(*(p+1)=='+' || *(p+1)=='#') {	/* SHARP */
+						offset+=1;
+						p++;
+						i=1;
+					}
+					if(*(p+1)=='-') {					/* FLAT */
+						offset-=1;
+						p++;
+						i=1;
+					}
+					if(*(p+1)=='.') {					/* Dotted note (1.5*notelen) */
+						dotted=1;
+						p++;
+						i=1;
+					}
+					if(isdigit(*(p+1))) {
+						out=numbuf;
+						while(isdigit(*(p+1))) {
+							*(out++)=*(p+1);
+							p++;
+						}
+						*out=0;
+						notelen=atoi(numbuf);
+						i=1;
+					}
+				}
+				if(notenum==0) {
+					out=strchr(octave,note);
+					if(out==NULL) {
+						notenum=-1;
+						offset=1;
+					}
+					else {
+						notenum=cterm.octave*12+1;
+						notenum+=(out-octave);
+					}
+				}
+				notenum+=offset;
+				playnote(notenum,notelen,dotted);
+				break;
+			case '<':							/* Down one octave */
+				cterm.octave--;
+				if(cterm.octave<0)
+					cterm.octave=0;
+				break;
+			case '>':							/* Up one octave */
+				cterm.octave++;
+				if(cterm.octave>6)
+					cterm.octave=6;
+				break;
+		}
+	}
 	cterm.music=0;
+	cterm.musicbuf[0]=0;
 }
 
 void scrolldown(void)
@@ -519,6 +785,11 @@ void cterm_init(int height, int width, int xpos, int ypos, int backlines, unsign
 	cterm.escbuf[0]=0;
 	cterm.sequence=0;
 	cterm.music=0;
+	cterm.tempo=120;
+	cterm.octave=4;
+	cterm.notelen=4;
+	cterm.noteshape=CTERM_MUSIC_NORMAL;
+	cterm.musicfore=TRUE;
 	cterm.backpos=0;
 	cterm.backlines=backlines;
 	cterm.scrollback=scrollback;
@@ -648,9 +919,17 @@ char *cterm_write(unsigned char *buf, int buflen, char *retbuf, int retsize)
 					}
 				}
 				else if (cterm.music) {
-					strcat(cterm.musicbuf,ch);
 					if(ch[0]==14)
 						play_music();
+					else {
+						if(strchr(musicchars,ch[0])!=NULL)
+							strcat(cterm.musicbuf,ch);
+						else {
+							/* Kill non-music strings */
+							cterm.music=0;
+							cterm.musicbuf[0]=0;
+						}
+					}
 				}
 				else {
 					switch(buf[j]) {
diff --git a/src/conio/cterm.h b/src/conio/cterm.h
index d16292134c7113dadacba3649040e8c9b01eaa5a..6f77f7329fa9cdf0a8933fc6c5af59f408772bfb 100644
--- a/src/conio/cterm.h
+++ b/src/conio/cterm.h
@@ -34,6 +34,12 @@
 #ifndef _CTERM_H_
 #define _CTERM_H_
 
+enum {
+	 CTERM_MUSIC_NORMAL
+	,CTERM_MUSIC_LEGATO
+	,CTERM_MUSIC_STACATTO
+};
+
 struct cterminal {
 	int	height;
 	int	width;
@@ -47,6 +53,11 @@ struct cterminal {
 	int	sequence;
 	char	musicbuf[1024];
 	int music;
+	int	tempo;
+	int	octave;
+	int notelen;
+	int noteshape;
+	int musicfore;
 	char *scrollback;
 	int backpos;
 	int backlines;