home *** CD-ROM | disk | FTP | other *** search
-
- /* ----- ZX Spectrum Tape Converter ---------------------------------------------
-
- This program reads ZX Spectrum program and data tapes and converts
- them into 'Tape' files for many ZX Spectrum emulators
-
- Final Release - Version 1.0.3
-
- *** Copyright (C) 1994-1995 Günter Woigk alias KIO !
- snail mail: Günter Woigk; Nürnberger Str. 79; 91052 Erlangen; Germany
- e-mail: ea215@fim.uni-erlangen.de
-
- 01.07.94 started work (KIO !)
- 25.11.94 killed my audio input with high voltage on protective ground
- virtually nothing is impossible! (KIO !)
- 17.12.94 last review - Bach composed masterpieces being deaf (KIO !)
- 21.01.95 replaced old tape file format with .tap file format (KIO !)
- 22.01.95 added code to set sound input to mono/8bit/22kHz (KIO !)
- 26.Feb.95 Metrowerk C version (KIO !)
-
- *** This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- *** This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- See the GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include <ToolUtils.h>
- #include <resources.h>
- #include <soundinput.h>
- #include <palettes.h>
- #include <files.h>
- #include <types.h>
- #include <FixMath.h>
- #include <quickdraw.h>
- #include "kio.h"
- #include "mem.h"
- #include "application.h"
- #include "eventloop.h"
- #include "console.h"
-
- // ----- General settings --------------------------------------------------
- short verbose = 1; // verbosity
-
- // ----- Settings for signal decoding -------------------------------------
- #define minh 10 // min. length for 1/2 header period (10)
- #define maxh 17 // max. length for 1/2 header period (16)
-
- #define mins 2 // min. length for 1/2 sync (3)
- #define maxs 9 // max. length for 1/2 sync (9)
-
- #define min0 2 // min. length for 1/2 0-bit period (3)
- #define max0 9 // max. length for 1/2 0-bit period (9)
-
- #define min1 6 // min. length for 1/2 1-bit periode (6)
- #define max1 16 // max. length for 1/2 1-bit periode (14)
-
- #define mn 2 // minimal codable run length (2)
- #define mx 17 // mn+15
- #define llsize 19 // mx+mn
-
- // ----- The Spectrum window -----------------------------------------------
- short show_spectrum = true;
- WindowPtr spectrumfenster = nil;
- RgnHandle borderRgn = nil;
- RgnHandle screenRgn = nil;
- CGrafPtr screenshot = nil;
- Char* spectrumbitmap = nil;
- Boolean flashing = false;
- short flashphase = 0;
- short borderstate = 0;
- #define spectrumID 129 // Resource ID of window
- short hborder = 32; // 16*n; border left & right for spectrum window
- short vborder = 16; // 16*n; border top & bottom for spectrum window
- long idxp[512]; // konvertiert attr+flashing -> paper color index
- long idxi[512]; // konvertiert attr+flashing -> ink color index
- RGBColor rgb[16]; // rgb colors
-
- // ----- Statistics window #1: Byte distribution -----------------------------------
- short show_distribution = 0;
- WindowPtr bytedistributionwindow = nil;
- #define statistikID 130 // resource ID
- long cnt[256]; // for calculating
-
- // ----- Statistics window #2: Run length distribution -----------------------------
- short show_run_length = 1;
- WindowPtr runlengthwindow = nil;
- #define statistik2ID 131
- long hi[llsize], lo[llsize]; // for calculating
-
- // ----- Sound recording -----------------------------------------------------------
- short plth_volume = 1; // play through volume
- short auto_gain_control = 0; // automatic gain control ?
-
- // ----- Used files ---------------------------------------------------------------
- FSSpec soundfile; // AIFF File containing sound data
- FSSpec rlesfile; // run legth encoded square wave sound
- FSSpec tapefile; // segment header framed binary data
- FSSpec logfile;
- short soundID = 0;
- short tapeID = 0;
- short dataID = 0;
-
- short oDocNumTypes = 2; // number of file types to use for OPEN
- SFTypeList oDocTypeList = {'AIFF','RLES',0,0}; // list of file types
-
- // ----- "Local" Variables for LoadTape() -------------------------------------------
- Char crc, *p, *d; // used inside LoadTape()
- Char* mh = nil; // Buffer for rle-Bytes to decode; inside LoadTape()
- Char* dh = nil; // Buffer for decoded Bytes; inside LoadTape()
-
- // ----- Event Loop ---------------------------------------------------------------
- Boolean done = false; // done:=TRUE to QuitApplication()
- long eventDelay = 999; // delay/60s until HandleNull() called
- RgnHandle eventRegion = nil; // fence for HandleREGION() calls
- EventRecord event; // event returned by WaitNextEvent
-
- // ----- Menu bar -------------------------------------------------------------------
- short mApple = 128;
- short iAbout = 1;
- short iHelp = 2;
- short mFile = 129;
- short iNew = 1;
- short iOpen = 2;
- short iSave = 3;
- short iClose = 4;
- short iPrint = 99;
- short iQuit = 6;
- short mEdit = 130;
- short iUndo = 1;
- short iCut = 3;
- short iCopy = 4;
- short iPaste = 5;
- short mOptions = 131;
-
- // ----- et cetera ----------------------------------------------------------------
- #define mem_magic 'KIO!'
-
-
- // ----- prototypes ---------------------------------------------------------------
- CloseAll();
- PrintNum ( long n ) ;
- ErrMsg ( Str255 s );
- long *Malloc ( Char **pp, long n );
- MFree ( Char **pp );
- AddItem ( MenuHandle m, Str255 eng, Str255 deu );
- InitSpectrumColors();
- RedrawFlashingColors();
- RedrawSpectrumscreen();
- RedrawSpectrumborder ();
- RefreshSpectrumfenster();
- CloseSpectrumWindow ();
- OpenSpectrumWindow();
- RefreshByteDistributionWindow();
- CloseStatistikfenster ();
- OpenByteDistributionWindow ( );
- CloseRunLengthWindow ();
- RefreshRunLengthWindow();
- OpenRunLengthWindow ( );
- HandleSomeMouseDown();
- RefreshWindows();
- DisplayScreenshot();
- Notify ( Str255 eng, Str255 ger );
- Short NextByte (Boolean v);
- ChangeBorder ( long n );
- LoadTape();
- RunLengthCompression();
-
-
- /* ********************************************************************** */
- /* ****************** S U B R O U T I N E S ******************** */
- /* ********************************************************************** */
-
-
- // ----- Close all files -------------------------------------------------------
- CloseAll()
- { if (soundID) { FSClose(soundID); soundID=0; };
- if (tapeID) { FSClose(tapeID); tapeID=0; };
- if (dataID) { FSClose(dataID); dataID=0; };
- }
-
-
- // ----- Print number ----------------------------------------------------------
- PrintNum ( long n )
- { Str255 s;
- NumToString ( n, s );
- ConPrint(s,0);
- }
-
-
- // ----- Print standard error message -------------------------------------------
- ErrMsg ( Str255 s )
- { ConPrint("\pAn error occured: ","\pEin Fehler ist aufgetreten: ");
- ConMsg(s,0);
- }
-
-
- // ----- Allocate n bytes and lock 'em ------------------------------------------
- // pp -> Master pointer for memory block
- // if *pp is not nil on entry, the old memory block will be released first
- long *Malloc ( Char **pp, long n )
- { long **h; OSErr err;
- if ( *pp != nil ) MFree(pp);
- h = (long**)TempNewHandle(n+8, &err);
- if ( h==nil || err ) return; // Master pointer = *pp := nil
- HLock ( (Handle)h ); // don't move around
- (*h)[0] = mem_magic; // private mem_hdr: magic
- (*h)[1] = (long)h; // private mem_hdr: backpointer to handle
- *pp = ((Char*)*h)+8; // Master pointer = *pp := address of buffer + 8
- }
-
- // ----- Release memory block -------------------------------------------------
- // pp -> Master pointer of the memory block
- MFree ( Char **pp )
- { long *p;
- if ( *pp == nil ) return; // there's nothing
- p = (*((long**)pp))-2; // p -> private mem_hdr
- *pp = nil; // clear pointer
- if ( p[0] != mem_magic ) return; // internal error !
- p[0] = 0; // clear magic
- DisposeHandle ( (Handle)p[1] ); // release memory
- }
-
-
- /* *************************************************************************** */
- /* ******************** A P P L I C A T I O N *********************** */
- /* *************************************************************************** */
-
-
- AddItem ( MenuHandle m, Str255 eng, Str255 deu )
- {
- if ( (german&&deu) || !eng ) AppendMenu ( m, deu );
- else AppendMenu( m, eng );
- }
-
- InitMenuBar ()
- { MenuHandle am, fm, em, om;
- am = NewMenu ( mApple, "\p\024" );
- fm = NewMenu ( mFile, "\pFile" );
- em = NewMenu ( mEdit, "\pEdit" );
- om = NewMenu ( mOptions, "\pOptions" );
-
- AddItem ( am, "\pAbout ZX Tape Loader ...","\pÜber den ZX Loader ..." );
- AddResMenu ( am, 'DRVR' );
-
- AddItem ( fm, "\pRecord new sound/N", "\pNeuen Sound aufnehmen/N" );
- AddItem ( fm, "\pOpen file/O", "\pDatei öffnen/O" );
- AddItem ( fm, "\pSave file/S", "\pDatei speichern/S" );
- AddItem ( fm, "\pClose top window/W", "\pOberstes Fenster schließen/W" );
- AppendMenu ( fm, "\p-" );
- AddItem ( fm, "\pQuit/Q", "\pProgramm beenden/Q" );
-
- AddItem ( om, "\pSpeaker off", "\pLautsprecher aus" );
- AddItem ( om, "\pSpeaker on", "\pLautsprecher ein" );
- AppendMenu ( om, "\p-" );
- AddItem ( om, "\pMaximum recording volume", "\pMaximale Aufnahmelautstärke" );
- AddItem ( om, "\pAutomatic gain control", "\pAutomatische Aussteuerung" );
- AppendMenu ( om, "\p-" );
- AddItem ( om, "\pShort protocol", "\pKurzes Protokoll" );
- AddItem ( om, "\pMedium protocol", "\pNormales Protokoll" );
- AddItem ( om, "\pLong protocol", "\pAusführliches Protokoll" );
- AppendMenu ( om, "\p-" );
- AddItem ( om, "\pByte distribution window off", "\pByteverteilungsstatistik aus" );
- AddItem ( om, "\pByte distribution window on", "\pByteverteilungsstatistik ein" );
- AppendMenu ( om, "\p-" );
- AddItem ( om, "\pRun length distribution window off", "\pPhasenlängenstatistik aus" );
- AddItem ( om, "\pRun length distribution window on", "\pPhasenlängenstatistik ein" );
- AppendMenu ( om, "\p-" );
- AddItem ( om, "\pZX Spectrum window off", "\pZX Spectrum Fenster aus" );
- AddItem ( om, "\pZX Spectrum window on", "\pZX Spectrum Fenster ein" );
-
- InsertMenu ( am, 0 );
- InsertMenu ( fm, 0 );
- InsertMenu ( em, 0 );
- InsertMenu ( om, 0 );
- DrawMenuBar();
- }
-
-
- // ===== Quit program ======================================================
- HandleQUIT()
- {
- done = 1;
- }
-
-
- // ===== Initialize application ===================================================
- HandleINIT(long how) // how = 'OAPP' or 'ODOC'
- {
- ConMsg("\p**** THE LONG AWAITED ZX SPECTRUM LOADER !",0);
- ConMsg("\p**** Version 1.0 Copyright (c) 1994 G.Woigk",0);
- ConNL();
- ConMsg("\p**** Read in Your ZX Spectrum Tapes to Harddisk", "\p**** Speichert ZX Spectrum Kassetten auf Harddisk");
- ConMsg("\p**** Free for non commercial use & distribution", "\p**** Frei für private Verwendung und Vertrieb");
- ConNL();
- ConMsg("\pThis program is free software; you can redistribute",0);
- ConMsg("\pit and/or modify it under the terms of the GNU",0);
- ConMsg("\pGeneral Public License as published by the Free",0);
- ConMsg("\pSoftware Foundation; either version 2 of the",0);
- ConMsg("\pLicense, or (at your option) any later version.",0);
- ConNL();
- ConMsg("\pThis program is distributed in the hope that it will",0);
- ConMsg("\pbe useful, but WITHOUT ANY WARRANTY; without even",0);
- ConMsg("\pthe implied warranty of MERCHANTABILITY or FITNESS",0);
- ConMsg("\pFOR A PARTICULAR PURPOSE. See the GNU General Public",0);
- ConMsg("\pLicense for more details.",0);
- ConNL();
- ConMsg("\pYou should have received a copy of the GNU General",0);
- ConMsg("\pPublic License along with this program; if not,",0);
- ConMsg("\pwrite to the Free Software Foundation, Inc.,",0);
- ConMsg("\p675 Mass Ave, Cambridge, MA 02139, USA.",0);
- ConNL();
- ConMsg("\pGünter Woigk; Nürnberger Str. 79; D-91052 Erlangen",0);
- ConMsg("\pe-mail: ea215@fim.uni-erlangen.de",0);
- ConNL();
- ConCrsr(true);
-
- HandleMENU(131,2); // speaker := on
- HandleMENU(131,4); // volume := max
- HandleMENU(131,8); // verbosity := medium
- HandleMENU(131,11); // don't show byte distribution window
- HandleMENU(131,15); // show run length distribution window
- HandleMENU(131,18); // show Spectrum window
-
- InitSpectrumColors();
- OpenSpectrumWindow();
- }
-
-
- // ----- Refresh window -----------------------------------------------
- HandleUPDATE(WindowPtr window)
- {
- if (window==conWindow) return ConRfsh();
- if (window==bytedistributionwindow) return RefreshByteDistributionWindow();
- if (window==runlengthwindow) return RefreshRunLengthWindow();
- if (window==spectrumfenster) return RefreshSpectrumfenster();
- }
-
-
- // ----- Close top window ----------------------------------------------
- HandleCLOSE()
- {
- if (FrontWindow()==conWindow) return ConClose();
- if (FrontWindow()==bytedistributionwindow) return CloseStatistikfenster();
- if (FrontWindow()==runlengthwindow) return CloseRunLengthWindow();
- if (FrontWindow()==spectrumfenster) return CloseSpectrumWindow();
- }
-
-
- // ----- Null Event: Flash flashing colors ----------------------------------------
- HandleNULL()
- { static Long oldTick=0; Long tick;
-
- if ( !spectrumfenster || !spectrumbitmap || !flashing ) // nothing to do
- { eventDelay = 120;
- return;
- };
-
- tick=TickCount();
- if ( tick >= oldTick+64 )
- { oldTick=tick;
- RedrawFlashingColors();
- flashphase = 256 - flashphase; // toggle 0 <-> 256
- };
- eventDelay = 64 - (tick & 63);
- }
-
- // ----- Open "Tape", "RLES" or "AIFF" file ------------------------------------
- HandleOPEN(FSSpec file)
- { OSErr err; FInfo info; long i;
-
- ConPrint("\pOpen file: ","\pÖffne Datei: "); ConMsg(file.name,0);
-
- err = FSpGetFInfo ( &file, &info );
- if (err) return ErrMsg("\pFSpGetFInfo()");
-
- CloseAll();
- ConCrsr(false); // no cursor to indicate 'busy'
-
- if (info.fdType=='AIFF') // Sound-File
- { soundfile = file;
- OpenByteDistributionWindow();
- CloseAll();
- RunLengthCompression();
- CloseAll();
- }
- else if (info.fdType=='RLES') // run length compressed square wave sound file
- { rlesfile = file;
- CloseStatistikfenster();
- }
- else
- { ConMsg("\pThis cannot happen!",0);
- ConCrsr(true);
- return;
- };
-
- OpenRunLengthWindow();
- CloseAll();
- LoadTape();
- CloseAll();
- ConNL();
- ConCrsr(TRUE);
- }
-
-
- // ----- Handle menu selection -----------------
- HandleMENU ( long menu, long item )
- { MenuHandle m;
- if ( menu==mOptions )
- { m = GetMHandle(menu); if (!m) return;
- switch (item)
- { case 1: // Speaker off
- case 2: // Speaker on
- plth_volume = item-1;
- CheckItem ( m, 1, !plth_volume );
- CheckItem ( m, 2, plth_volume );
- break;
- case 4: // max. volume
- case 5: // autom. gain control
- auto_gain_control = item-4;
- CheckItem ( m, 4, !auto_gain_control );
- CheckItem ( m, 5, auto_gain_control );
- break;
- case 7: /* verbose 0 */
- case 8: /* verbose 1 */
- case 9: /* verbose 2 */
- verbose = item-7;
- CheckItem ( m, 7, verbose==0 );
- CheckItem ( m, 8, verbose==1 );
- CheckItem ( m, 9, verbose==2 );
- break;
- case 11: /* hide byte distribution */
- CloseStatistikfenster();
- case 12: /* show byte distribution */
- show_distribution = item-11;
- CheckItem ( m, 11, !show_distribution);
- CheckItem ( m, 12, show_distribution);
- break;
- case 14: /* hide run length distribution */
- CloseRunLengthWindow();
- case 15: /* show run length distribution */
- show_run_length = item-14;
- CheckItem ( m, 14, !show_run_length);
- CheckItem ( m, 15, show_run_length);
- break;
- case 17: /* hide specci */
- CloseSpectrumWindow();
- case 18: /* show speci */
- show_spectrum = item-17;
- CheckItem ( m,17, !show_spectrum);
- CheckItem ( m,18, show_spectrum);
- break;
- };
- return;
- };
- }
-
-
- // *********************************************************************
- // Handling the Spectrum window
- // *********************************************************************
-
-
- // ----- Init Spectrum color tables ------------------------------------
- InitSpectrumColors()
- { Short c,i;
-
- for ( i=0; i<16; i++ ) // rgb tables
- { c=0xcccc; if (i>=8) c=0xffff;
- rgb[i].blue = (i&1) ? c : 0;
- rgb[i].red = (i&2) ? c : 0;
- rgb[i].green = (i&4) ? c : 0;
- };
-
- for ( i=0; i<128; i++ )
- { idxi[i] = idxi[i+128] = idxi[i+256] = idxp[i+384] = (i&7)+((i>>3)&8);
- idxp[i] = idxp[i+128] = idxp[i+256] = idxi[i+384] = (i>>3)&0xf;
- };
- }
-
-
- // ----- Redraw flashing character positions -----------------------------------
- RedrawFlashingColors()
- { short x,y,i,j; Char *attr; Pattern p; Rect r;
-
- if ( !spectrumfenster || !spectrumbitmap || !flashing ) return; // nothing to do
-
- SetPort ( spectrumfenster );
-
- attr = spectrumbitmap+6144;
- SetRect ( &r, hborder,vborder, hborder+8,vborder+8 );
- for ( y=0; y<24; y++ )
- { for ( x=0; x<32; x++ )
- { if (*attr&0x80)
- { RGBForeColor ( rgb + idxi[flashphase+*attr] );
- RGBBackColor ( rgb + idxp[flashphase+*attr] );
- j = ((y&0x0007)<<5) + ((y&0x0018)<<8) + x;
- for ( i=0; i<8; i++ )
- { p.pat[i] = spectrumbitmap[j];
- j += 256;
- };
- FillRect ( &r, &p );
- };
- attr++; r.left+=8; r.right+=8;
- };
- r.left=hborder; r.right=hborder+8;
- r.top+=8; r.bottom+=8;
- };
- }
-
-
- // ----- Redraw the inner part of the Spectrum window --------------------------
- RedrawSpectrumscreen()
- { short x,y,i,j; Char *attr; Pattern p; Rect r;
-
- if (!spectrumfenster) return; // not open
-
- SetPort ( spectrumfenster );
-
- if (spectrumbitmap) // there's a picture to show
- { attr = spectrumbitmap+6144;
- SetRect ( &r, hborder,vborder, hborder+8,vborder+8 );
- for ( y=0; y<24; y++ )
- { for ( x=0; x<32; x++ )
- { RGBForeColor ( rgb + idxi[flashphase+*attr] );
- RGBBackColor ( rgb + idxp[flashphase+*attr] );
- j = ((y&0x0007)<<5) + ((y&0x0018)<<8) + x;
- for ( i=0; i<8; i++ )
- { p.pat[i] = spectrumbitmap[j];
- j += 256;
- };
- FillRect ( &r, &p );
- attr++; r.left+=8; r.right+=8;
- };
- r.left=hborder; r.right=hborder+8;
- r.top+=8; r.bottom+=8;
- };
- }
- else
- {
- ForeColor ( whiteColor );
- PaintRgn ( screenRgn );
- ForeColor ( blackColor );
- BackColor ( whiteColor );
- MoveTo ( hborder+1,vborder+190 );
- DrawString ( "\p(C) 1982 Sinclair Corporation");
- };
- }
-
-
- // ----- Redraw Border of Spectrum window ----------------------------
- // borderstate 0 = normal
- // 1 = white 3 = red-white
- // 2 = red 4 = blue-yellow
- RedrawSpectrumborder ()
- { RgnHandle oldClipRgn;
- Rect border, box;
- short i;
-
- if (!spectrumfenster) return; // window not open
-
- SetPort(spectrumfenster);
- oldClipRgn=NewRgn();
- GetClip(oldClipRgn);
- SetClip(borderRgn);
- border = spectrumfenster->portRect;
-
- switch (borderstate)
- { case 1: // search header indicator
- ForeColor ( whiteColor );
- PaintRect ( &border );
- break;
- case 2: // blips detect indicator
- ForeColor ( redColor );
- PaintRect ( &border );
- break;
- case 3: // header indicator
- ForeColor ( redColor );
- PaintRect ( &border );
- ForeColor ( whiteColor );
- box=border;
- for ( i=1; i<border.bottom; i+=9 )
- { box.top=i;box.bottom=i+4;
- PaintRect ( &box );
- };
- break;
- case 4: // data indicator
- ForeColor (yellowColor );
- PaintRect ( &border );
- ForeColor ( blueColor );
- box=border;
- for ( i=1; i<border.bottom; i+=4 )
- { box.top=i;box.bottom=i+2;
- PaintRect ( &box );
- };
- break;
- default: // normal border
- if (spectrumbitmap) // fit border to picture
- { Char* attr, a,b,c,d;
- attr = spectrumbitmap+6144;
- a = attr[0]&0x78;
- b = attr[31]&0x78;
- c = attr[672]&0x78;
- d = attr[703]&0x78;
- if ( a==b || a==c || a==d ) {}
- else if ( b==c || b==d ) a=b;
- else if ( c==d ) a=c;
- RGBForeColor ( rgb + (a>>3) );
- PaintRect ( &border );
- }
- else // default border = default paper = white
- { ForeColor ( whiteColor );
- PaintRect ( &border );
- };
- break;
- };
-
- SetClip ( oldClipRgn );
- DisposeRgn(oldClipRgn);
- }
-
-
- // ----- Update ZX Spectrum window ------------------------------------
- RefreshSpectrumfenster()
- {
- RedrawSpectrumscreen();
- RedrawSpectrumborder();
- }
-
-
- // ----- Close window -------------------------------------------------
- // if a picture is valid, it's not discarded, only the window is closed
- CloseSpectrumWindow ()
- {
- if (spectrumfenster)
- { DisposeWindow ( spectrumfenster );
- spectrumfenster=nil;
- };
- }
-
-
- // ----- Open ZX Spectrum window ----------------------------------------
- // Opens the window only, if checked in menu (default)
- // If a valid picture is present, it will be displayed
- // If already open, it stays open in any case
- OpenSpectrumWindow()
- { Rect mybox,border,screen; short i;
-
- borderstate=0;
-
- if (!show_spectrum) return; // option not checked in menu
-
- if (!borderRgn) borderRgn = NewRgn();
- if (!screenRgn) screenRgn = NewRgn();
- if ( ! (screenRgn && borderRgn) ) return; // memory low
-
- if (!spectrumfenster)
- { spectrumfenster = GetNewCWindow ( spectrumID, nil, (WindowPtr)-1 );
- if (!spectrumfenster) return ConMsg("\pCannot open the ZX Spectrum window","\pFehler beim Öffnen des ZX Spectrumfensters");
- hborder = ((spectrumfenster->portRect.right-256)/16)*8; if (hborder<=0) hborder=8;
- vborder = ((spectrumfenster->portRect.bottom-192)/16)*8; if (vborder<=0) vborder=8;
- SizeWindow ( spectrumfenster, 256+2*hborder, 192+2*vborder, true );
- ShowWindow ( spectrumfenster );
- };
-
- SetPort ( spectrumfenster );
- GetFNum("\pMonaco",&i);
- TextFont(i);
- TextMode(srcCopy);
- TextSize(9);
-
- screen=border=spectrumfenster->portRect;
- InsetRect ( &screen, hborder, vborder );
- RectRgn ( screenRgn, &screen );
- RectRgn ( borderRgn, &border );
- XorRgn ( borderRgn, screenRgn, borderRgn );
-
- RedrawSpectrumborder();
- RedrawSpectrumscreen();
- }
-
-
- // ===== Handling the byte distribution window ======================================
-
-
- // ----- Refresh byte distribution window -----------------------------------------
- RefreshByteDistributionWindow()
- { short x,y; long mxm;
-
- if (!bytedistributionwindow) return;
-
- SetPort(bytedistributionwindow);
- EraseRect ( &bytedistributionwindow->portRect );
-
- mxm=0;
- for (x=0; x<256; x++) if (cnt[x]>mxm) mxm = cnt[x];
- mxm/=100; if (mxm<=0) return;
-
- for (x=0; x<256; x++)
- { MoveTo(x+3,118);
- LineTo(x+3,118-cnt[x]/mxm);
- };
- }
-
-
- // ----- Close byte distribution window ---------------------------------------------
- // statistical data is not discarded, only the window is closed
- CloseStatistikfenster ()
- {
- if (bytedistributionwindow)
- { DisposeWindow ( bytedistributionwindow );
- bytedistributionwindow=nil;
- };
- }
-
-
- // ----- Calculate and display new byte distribution statistic ------------------------
- // source is soundfile
- OpenByteDistributionWindow ( )
- { OSErr err; long i,j, len, n;
- char buffer[10000];
- Rect mybox;
-
- if (!show_distribution) return; // not selected
-
- if (!bytedistributionwindow)
- { bytedistributionwindow = GetNewWindow ( statistikID, nil, (WindowPtr)-1 );
- if (!bytedistributionwindow) return ConMsg("\pCannot open the byte distribution window","\pFehler beim Öffnen des Byteverteilungsfensters");
- SizeWindow(bytedistributionwindow, 262,120,true);
- ShowWindow(bytedistributionwindow);
- };
-
- ConMsg ("\pByte distribution is calculated...","\pByteverteilungsstatistik wird erzeugt.");
-
- for ( i=0; i<256; i++ ) cnt[i]=0;
- RefreshByteDistributionWindow(); // Erase the window
-
- err = FSpOpenDF ( &soundfile, fsCurPerm, &soundID );
- if (err) soundID=0;
- if (err) return ErrMsg("\pFSpOpenDF()");
-
- err = GetEOF ( soundID, &len );
- if (err) return ErrMsg("\pGetEOF()");
-
- for ( i=0; i<=len; i+=10000 )
- { n=10000;
- err = FSRead ( soundID, &n, buffer );
- if ( (err==eofErr) & (i+n==len) ) err=noErr;
- if (err) return ErrMsg("\pFSRead()");
- for ( j=0; j<n; j++ ) cnt[buffer[j]+128]++;
- RefreshWindows();
- }
-
- RefreshByteDistributionWindow();
- }
-
-
- // ===== Handling the run length distribution window ==============================
-
-
- // ----- Close run length distribution window -------------------------------------------------
- // actual data is not discarded, only the window is closed!
- CloseRunLengthWindow ()
- {
- if (runlengthwindow)
- { DisposeWindow ( runlengthwindow );
- runlengthwindow=nil;
- };
- }
-
-
- // ----- Refresh run length distribution window -----------------------------------------
- RefreshRunLengthWindow()
- { short x,y; long mxm; Rect mybox; short hscale, vscale;
-
- if (!runlengthwindow) return; // window not open
-
- SetPort ( runlengthwindow );
- EraseRect ( &runlengthwindow->portRect );
-
- hscale=256/llsize; vscale=55;
-
- mxm=0;
- for (x=0; x<llsize; x++) { if (hi[x]>mxm) mxm = hi[x]; if (lo[x]>mxm) mxm = lo[x]; };
- mxm/=vscale; if (mxm<=0) return;
-
- for (x=0; x<llsize; x++)
- { SetRect ( &mybox, 3+x*hscale, 60-1-((hi[x]+mxm/2)/mxm), 2+(x+1)*hscale, 60+2+((lo[x]+mxm/2)/mxm) );
- InvertRect ( &mybox );
- };
- SetRect ( &mybox, 3, 60-1, 2+llsize*hscale, 60 );
- EraseRect ( &mybox );
- SetRect ( &mybox, 3, 60+1, 2+llsize*hscale, 60+2 );
- EraseRect ( &mybox );
- }
-
-
- // ----- Calculate and display new run length distribution statistic ------------------------
- // source is rlesfile
- OpenRunLengthWindow ( )
- { OSErr err; long i,j,k, len, n;
- Char buffer[10000];
- Rect mybox;
-
- if (!show_run_length) return; // not selected in menu
-
- if (!runlengthwindow)
- { runlengthwindow = GetNewWindow ( statistik2ID, nil, (WindowPtr)-1 );
- if (!runlengthwindow) return ConMsg("\pCannot open run length distribution window","\pFehler beim Öffnen des Lauflängenfensters");
- SizeWindow(runlengthwindow, 262,120,true);
- ShowWindow(runlengthwindow);
- };
-
- ConMsg ("\pRun length distribution is calculated...","\pLauflängenstatistik wird erzeugt.");
-
- for ( i=0; i<llsize; i++ ) hi[i]=lo[i]=0;
- RefreshRunLengthWindow(); // clear window
-
- err = FSpOpenDF ( &rlesfile, fsCurPerm, &tapeID );
- if (err) tapeID=0;
- if (err) return ErrMsg("\pFSpOpenDF()");
-
- err = GetEOF ( tapeID, &len );
- if (err) return ErrMsg("\pGetEOF()");
-
- for ( i=0; i<len; i+=10000 )
- { n=10000;
- err = FSRead ( tapeID, &n, buffer );
- if ( (err==eofErr) & (i+n==len) ) err=noErr;
- if (err) return ErrMsg("\pFSRead()");
-
- for ( j=0; j<n; )
- { k = buffer[j++];
- hi[(k>>4)+mn] += 1;
- lo[(k&0x0f)+mn] +=1;
- };
-
- RefreshWindows();
- }
-
- RefreshRunLengthWindow();
- }
-
-
- // ==========================================================================================
-
-
- // ----- Handle some mouse down events --------------------------------
- HandleSomeMouseDown()
- { WindowPtr window;
- long where;
- where = FindWindow ( event.where, &window );
- switch (where)
- {
- // case inMenuBar: HandleMenuSelection ( MenuSelect( event.where ) ); return;
- case inMenuBar: SysBeep(4711); return;
- case inDrag: DragWindow ( window, event.where, &qd.screenBits.bounds ); return;
- case inSysWindow: SystemClick ( &event, window ); return;
- case inGoAway: HandleCLOSE(); return;
- case inGrow: HandleGROW(); return;
- case inZoomIn: HandleZOOMIN(); return;
- case inZoomOut: HandleZOOMOUT(); return;
- case inContent: SelectWindow (window); HandleINCONTENT(); return;
- case inDesk: HandleINDESK(); return;
- };
- }
-
-
- // ----- Refresh windows if neccessary ----------------------------------
- RefreshWindows()
- { while ( WaitNextEvent(mDownMask|mUpMask|updateMask|activMask|osMask,&event,0,eventRegion) )
- { switch (event.what)
- {
- // case kHighLevelEvent: AEProcessAppleEvent(&event); break;
- case mouseDown: HandleSomeMouseDown(); break;
- // case autoKey: HandleAUTOKEY(event.message&0x0ff); break;
- /* case keyDown:
- if (event.modifiers&cmdKey)
- { selection = MenuKey(event.message&0x0ff);
- if (HiWord(selection))
- { HandleMenuSelection( selection );
- break;
- }
- }
- HandleKEYDOWN (event.message&0x0ff);
- break;
- */
- case activateEvt:
- SetPort ( (WindowPtr)event.message );
- if (event.modifiers&activeFlag)
- HandleACTIVATE (); // window activated
- else HandleDEACTIVATE (); // window deactivated
- break;
-
- case updateEvt:
- BeginUpdate ( (WindowPtr)event.message );
- HandleUPDATE((WindowPtr)event.message);
- EndUpdate ( (WindowPtr)event.message );
- break;
-
- case osEvt:
- if (event.message & 0x01000000 )
- if ( event.message & 0x00000001 )
- SetCursor(&qd.arrow),HandleRESUME(); // application re-activated
- else HandleSUSPEND(); // application de-activated
- if ((event.message & 0xFF000000)==0xFA000000)
- HandleREGION(); // mouse leaves eventRegion
- break;
-
- };
- };
- }
-
-
- // ------ Check new data in buffer for screen$ and if so, display it
- DisplayScreenshot()
- { Char *p,*e, *ph, *pd;
- Short slen;
- long len;
- Char *cp,*ep; long blklen,blkadr;
-
- if ( !dh ) return; // no data buffer
- if ( !spectrumfenster ) return; // window not open
-
- p = dh+4; // scan start
- e = *(Char**)dh; // scan end
- ph = nil; // ptr -> header block
- pd = nil; // ptr -> data block
-
- while (p<e)
- { ph=pd;
- pd=p;
- slen = *p + *(p+1)*256 -2;
- p += slen ? slen+4 : 0x10004;
- };
-
- if (ph==nil) return; // no header block found
-
- slen = *ph + *(ph+1)*256 -2;
- if ( slen < 17 ) return; // min. length for header: type+17byte+crc = 19 byte
- cp = ph+2; // cp -> type
- if ( *cp!=0 || *(cp+1)!=3 ) return; // not a code header
-
- blklen = *(cp+12) + (*(cp+13)<<8); // length of data block
- if (!blklen) blklen = 0x10000;
- blkadr = *(cp+14) + (*(cp+15)<<8); // original address of data block
-
- if ( (blklen!=6912) && ( (blkadr+blklen<0x4000) || (blkadr>=23296) ) ) return;
- if (blklen==6912) blkadr=0x4000; // sometimes they've saved it from anywhere in memory
-
- // This is a header for data, that might contain a screen$
-
- slen = *pd + *(pd+1)*256 -2;
- if ( slen < blklen ) return; // mismatch between data and header block
- cp = pd+2; // cp -> type
- if ( *cp!=255) return; // not a data block!
-
- // Anything seems to be all right ...
-
- cp = cp+1; // cp points to effective data
- if (blkadr<0x4000) { blklen-=(0x4000-blkadr); cp += (0x4000-blkadr); blkadr=0x4000; };
- if (blkadr+blklen > 23296) blklen = 23296-blkadr;
- if (blklen<=0) return; // this cannot happen
-
- Malloc ( &spectrumbitmap, 6912 );
- if (!spectrumbitmap) return; // out of memory
- memset ( spectrumbitmap, 0, 6144 ); // default pixel
- memset ( spectrumbitmap+6144, 0x38, 768); // default attribute
-
- memcpy ( spectrumbitmap + blkadr - 0x4000, cp, blklen ); // and overwrite
-
- cp=spectrumbitmap+6144; // flashing required ?
- ep=spectrumbitmap+6912;
- flashing=false;
- eventDelay=120;
- while ( cp<ep )
- { if ( *cp++&0x80 )
- { if ( (*(cp-1)&0x07)==((*(cp-1))>>3)&0x07 )
- *(cp-1) &=0x7f; // don't flash same colors
- else
- { flashing=true; eventDelay=60; break; };
- };
- }
-
- RedrawSpectrumscreen();
- }
-
-
- Notify ( Str255 eng, Str255 ger )
- {
- ConNL();
- PrintNum(p-mh);
- ConTab();
- ConPrint(eng,ger);
- }
-
-
- Short NextByte (Boolean v)
- { register Char b1,b2; short i,c;
- c=0;
- for (i=0;i<8;i++)
- { b1=*p++; // get 1/2 nibble
- b2=*p++; // get 2/2 nibble
- if (b1>max1 || b2>max1) { if (v) Notify("\p••••• Phase too long!","\p••••• Flanke zu lang!"); return(-1); };
- if (b1<min0 || b2<min0) { if (v) Notify("\p••••• Phase too short!","\p••••• Flanke zu kurz!"); return(-1); };
- if (b1<=max0 && b2<=max0) c = c+c;
- else if (b1>=min1 && b2>=min1) c = c+c+1;
- else
- { if (v) Notify("\p••••• Long and short phase for same bit!","\p••••• Kurze und lange Flanke für gleiches Bit!");
- return(-1);
- };
- };
- crc ^= c; // update checksum
- *d++=c; // and store byte in buffer
- return(c);
- }
-
-
- ChangeBorder ( long n )
- {
- borderstate=n;
- RedrawSpectrumborder();
- Delay ( 15, &n ); // for your eyes only ...
- RefreshWindows(); // don't get nervous !
- }
-
-
- // ----- Convert RLES -> Tape ----------------------------------------------
- LoadTape()
- { OSErr err; long i,n,len; Char *q, c; short b, typ; Short slen;
- Short expect=0;
- Char hdr[17];
- Char * dsp;
-
- ConMsg ("\pPrograms are loaded.","\pProgramme werden geladen.");
- MFree ( &spectrumbitmap );
- OpenSpectrumWindow();
-
- err = FSpOpenDF ( &rlesfile, fsCurPerm, &tapeID );
- if (err) tapeID=0;
- if (err) return ErrMsg("\pFSpOpenDF()");
-
- err = GetEOF ( tapeID, &len );
- if (err) return ErrMsg("\pGetEOF()");
-
- Malloc ( &mh, len*2 );
- if ( !mh ) return ConMsg("\pNo memory available!","\pKein Speicher mehr frei!");
-
- Malloc ( &dh, 200 + len/7 ); // benötigt werden: len/8 + gesamtgröße aller segmentköpfe
- if ( !dh ) MFree (&mh);
- if ( !dh ) return ConMsg("\pNo memory available!","\pKein Speicher mehr frei!");
-
- // ----- Read source file and prepare
- n=len; err = FSRead ( tapeID, &n, mh+len );
- if ( (err==eofErr) & (n==len) ) err=noErr;
- if (err)
- { ErrMsg("\pFSRead()");
- MFree ( &mh ); MFree ( &dh );
- return;
- };
-
- p = mh;
- q = p + len;
-
- for ( i=0; i<len; i++ )
- { *p++ = ( *q >> 4 ) + 2;
- *p++ = ( *q++ & 0x0f ) + 2;
- };
-
- // ----- prepare destination buffer
- dsp = dh+4; // data segment pointer
- *(Char**)dh=dsp; // end of data pointer
-
- // ----- let's do it! ---------------------------------------------------
- p = mh; // read pointer
- q = p+len+len; // end pointer
-
- while (p<q)
- {
- nh: ChangeBorder(1); // we are looking for a header !
- if (verbose>=2) { ConNL(); Notify("\p Looking for header","\p Suche Vorspann"); };
- nhx: p++;
- if (p>=q) break;
- for (i=0; i<88; i++,p++ ) if (*p>maxh || *p<minh) break;
- if (i<88) goto nhx;
-
- ChangeBorder(2); // blips ... check it !
- for (i=0; i<444; i++,p++ ) if (*p>maxh || *p<minh) break;
- if (i<444) goto nh;
-
- ChangeBorder(3); // we've got it !
- if (verbose>=2) { Notify("\p Header ... ","\p Vorspann ... "); };
- while ( *p<=maxh && *p>=minh && p<q ) p++;
-
- if (*p>maxh) { if (verbose) { Notify("\p Header: Period too long", "\p Fangsequenz: Periode zu lang"); }; goto nh; };
- if (*p>maxs) { if (verbose) { Notify("\p Sync 1/2 too long", "\p Sync 1/2 zu lang"); goto nh; };};
- if (*p<mins) { if (verbose) { Notify("\p Sync 1/2 too short", "\p Sync 1/2 zu kurz"); goto nh; };}; p++;
- if (*p>maxs) { if (verbose) { Notify("\p Sync 2/2 too long", "\p Sync 2/2 zu lang"); goto nh; };};
- if (*p<mins) { if (verbose) { Notify("\p Sync 2/2 too short", "\p Sync 2/2 zu kurz"); goto nh; };}; p++;
- if (verbose>=2) { Notify("\p Sync pulse ... ","\p Syncimpuls ... "); };
-
- crc = 0; d = dsp+2;
- typ=NextByte(true); // read Block Type
- if (typ<0) goto nh;
- ChangeBorder(4);
-
- if (typ!=0) goto ld; // load data
-
- // Header
- if (expect) { Notify("\p••••• The data block wasn't found!","\p••••• Der Datenblock wurde nicht gefunden!");};
- expect=0;
- ConNL();Notify("\p***** HEADER",0);
- for (i=0; i<=16; i++ ) { hdr[i]=b=NextByte(true); if (b<0) goto nl; };
-
- typ = *hdr; *hdr=10; for (i=1;i<=10;i++) if (hdr[i]<32) hdr[i]='?';
-
- switch (typ)
- { case 0: Notify("\p Basic program", "\p Programmdatei"); break;
- case 1: Notify("\p Number array", "\p Zahlenarray"); break;
- case 2: Notify("\p Text array", "\p Textarray"); break;
- case 3: Notify("\p Code or Screen$", "\p Code oder Screen$"); break;
- default: Notify("\p Illegal header ID", "\p Ungültiger Headertyp");
- Notify("\p>>>>> Loading data as Long Header", "\p>>>>> Lade Daten als Long Header");
- i=1;expect=0;goto ldx;
- };
-
- if (hdr[1]==255) Notify("\p unnamed", "\p ohne Namen");
- else { Notify("\p Name: ",0); ConPrint(hdr,0); };
-
- Notify ("\p File length: ","\p Dateilänge: "); PrintNum(hdr[11]+((Short)hdr[12]<<8));
-
- if ( typ==0 && verbose )
- { if ( hdr[14]<0x0080 )
- { Notify ("\p Autostart at line: ","\p Autostart ab Zeile: "); PrintNum(hdr[13]+((Short)hdr[14]<<8));
- };
- Notify ("\p Program length without data: ","\p Programmlänge ohne Daten: ");
- PrintNum(hdr[15]+((Short)hdr[16]<<8));
- };
-
- if ( (typ==1 || typ==2) && verbose )
- {
- };
-
- if ( typ==3 && verbose )
- { Notify ("\p Original address of data: ", "\p Originallage der Daten: ");
- PrintNum(hdr[13]+((Short)hdr[14]<<8));
- };
-
- b=NextByte(true); if(b<0) goto nl;
- if (crc)
- { Notify("\p••••• Checksum wrong","\p••••• Prüfsumme stimmt nicht");
- b=NextByte(false); if (b<0) goto nl;
- b=NextByte(false); if (b<0) goto nl;
- Notify("\p>>>>> Long Header ... loading proceeds !","\p>>>>> Long Header ... lade weiter !");
- i=20; // number of bytes already read
- expect=0; // no read end marker
- goto ldx; // read "headerless"
- };
- Notify("\p+++++ Checksum ok","\p+++++ Prüfsumme ok");
- expect=hdr[11]+((Short)hdr[12]<<8);
- b=NextByte(false); if (b<0) goto nl;
- b=NextByte(false); if (b<0) goto nl;
- Notify("\p>>>>> Long Header ... loading proceeds !","\p>>>>> Long Header ... lade weiter !");
- i=20; // number of bytes already read
- expect=18; // last read end marker
- goto ldx; // read "headerless"
-
- // Data
- ld:
- if (typ!=255) { ConNL();Notify("\p$$$$$ UNDEFINED TYPE: ","\p$$$$$ UNDEFINIERTER TYP: "); PrintNum(typ); ConNL(); };
- if (expect)
- { ConNL(); Notify("\p***** DATA","\p***** DATEN");
- for ( i=0; i<expect && p<q; i++ )
- { b=NextByte(true); if (b<0) { expect=0; goto nl; };
- };
- b=NextByte(true); if (b<0) { expect=0; goto nl; };
- if (crc) { Notify("\p••••• Checksum wrong","\p••••• Prüfsumme stimmt nicht"); expect=0; }
- else Notify("\p+++++ Checksum ok","\p+++++ Prüfsumme ok");
- b=NextByte(false); if (b<0) { expect=0;goto nl;};
- b=NextByte(false); if (b<0) { expect=0;goto nl;};
- Notify("\p>>>>> Long Data ... loading proceeds !","\p>>>>> Long Data ... lade weiter !");
- i=i+2;
- goto ldx;
- }
- else
- { ConNL(); Notify("\p***** HEADERLESS DATA","\p***** HEADERLOSE DATEN");
- for ( i=0; p<q; i++ )
- {
- ldx: b=NextByte(!expect); if (b<0) break;
- if (crc==0)
- { if (verbose>=2) ConPrint("\p ((crc==0)) ",0);
- expect=i;
- };
- };
- Notify ("\p File length: ","\p Dateilänge: "); PrintNum(i-1);
- if (expect==0) { Notify("\p••••• Checksum wrong!","\p••••• Prüfsumme stimmt nicht!"); goto nl; };
- if (i-1==expect)
- { Notify ("\p+++++ Checksum ok","\p+++++ Prüfsumme ok");
- }
- else
- { Notify ("\p Last OK for checksum at: ","\p Letztes ok für die Prüfsumme: "); PrintNum(expect);
- Notify ("\p••••• Probably unusable!","\p••••• Vermutlich fehlerhaft!");
- };
- expect=0;
- goto nl;
- };
-
- // ----- update segment header
- nl: len = d-(dsp+2);
- if (len<3) // all blocks contain at least 3 bytes: 1*type+1*data+1*crc !!!
- { Notify ("\p••••• Block contains no data (skipped)","\p••••• Block enthält keine Daten (übersprungen)");
- d = dsp+2;
- continue;
- };
- if (len>=0x10002)
- { Notify ("\p••••• Block longer than 0x10000 bytes","\p••••• Block länger als 0x10000 Bytes");
- len=0x10002;
- d=dsp+0x10004;
- };
- *dsp = len; // big endian byte order !!!
- *(dsp+1) = len>>8; // .tap format was invented on PC clowns !
- *(Char**)dh = dsp = d;
- d += 2;
- DisplayScreenshot();
- };
-
- Notify("\p----- End of tape -----","\p----- Ende des Bandes -----"); ConNL();
-
- MFree ( &mh );
- ChangeBorder(0);
-
- // ----- write to destination file (type: 'Tape')
-
- ConTab();ConMsg("\p Writing tape file","\p Schreibe Banddatei");
- tapefile=rlesfile;
- if ( *tapefile.name>=5 )
- { if ( memcmp ( tapefile.name+*tapefile.name-4, ".rles", 5 ) == 0 ) *tapefile.name -=5;
- else if ( memcmp ( tapefile.name+*tapefile.name-4, ".RLES", 5 ) == 0 ) *tapefile.name -=5;
- }
- if (*tapefile.name>25) *tapefile.name=25;
- while (tapefile.name[*tapefile.name]==' ') *tapefile.name -= 1;
- memcpy ( tapefile.name+*tapefile.name+1, " .tape", 6 );
- *tapefile.name += 6;
-
- err = FSpCreate ( &tapefile, 'ZXSP', 'Tape', 0 ); // 'ZXSP' == ID of ZX Spectrum Emulator
- if (err=dupFNErr) err=noErr; // ignore file already exists
- if (err) return ErrMsg("\pFSpCreate()");
-
- err = FSpOpenDF ( &tapefile, fsCurPerm, &dataID );
- if (err=eofErr) err=noErr;
- if (err) return ErrMsg("\pFSpOpenDF()");
-
- err = SetEOF ( dataID, 0 ); // clear tape
- if (err) return ErrMsg("\pSetEOF()");
-
- len = *(Char**)dh-(dh+4);
- err = FSWrite ( dataID, &len, dh+4 );
- if (err) return ErrMsg("\pFSWrite()");
- }
-
-
- // ----- Convert Sound -> RLES ---------------------------------------------
- //
- RunLengthCompression()
- { OSErr err; long i,j,k, len, n,m; short whatsup; Char *z;
- char buffer[10000]; Char rll[10000];
- short hysterese = 2;
- Rect mybox;
-
- ConMsg ("\pRun length compression in progress...","\pLauflängenkompression wird durchgeführt.");
-
- err = FSpOpenDF ( &soundfile, fsCurPerm, &soundID );
- if (err) return ErrMsg("\pFSpOpenDF()");
-
- err = GetEOF ( soundID, &len );
- if (err) return ErrMsg("\pGetEOF()");
-
- rlesfile=soundfile;
- if ( *rlesfile.name>=5 )
- { if ( memcmp ( rlesfile.name+*rlesfile.name-4, ".aiff", 5 ) == 0 ) *rlesfile.name -=5;
- else if ( memcmp ( rlesfile.name+*rlesfile.name-4, ".AIFF", 5 ) == 0 ) *rlesfile.name -=5;
- }
- if (*rlesfile.name>25) *rlesfile.name=25;
- while (rlesfile.name[*rlesfile.name]==' ') *rlesfile.name -= 1;
- memcpy ( rlesfile.name+*rlesfile.name+1, " .rles", 6 );
- *rlesfile.name += 6;
-
- err = FSpCreate ( &rlesfile, 'ZXSp', 'RLES', 0 );
- if (err=dupFNErr) err=noErr; // ignore file already exists
- if (err) return ErrMsg("\pFSpCreate()");
-
- err = FSpOpenDF ( &rlesfile, fsCurPerm, &tapeID );
- if (err=eofErr) err=noErr;
- if (err) return ErrMsg("\p(FSpOpenDF)");
-
- err = SetEOF ( tapeID, 0 ); // clear tape
- if (err) return ErrMsg("\p(SetEOF)");
-
-
- k=1;whatsup='hi';z=rll;
- for ( i=0; i<len; i+=10000 )
- { n=10000;
- err = FSRead ( soundID, &n, buffer );
- if ( (err==eofErr) & (i+n==len) ) err=noErr;
- if (err) return ErrMsg("\p(FSRead)");
-
- for ( j=0; j<n; )
- { if (whatsup=='hi')
- { while ( j<n && buffer[j]>=-hysterese ) { j++; k++; };
- if ( j<n ) { if ( k>mx) k=mx; if (k<mn) k=mn; *z=(k-mn)<<4 ; whatsup='lo'; k=0; };
- };
- if (whatsup=='lo')
- { while ( j<n && buffer[j]<=hysterese ) { j++; k++; };
- if ( j<n ) { if ( k>mx) k=mx; if (k<mn) k=mn; *z+=k-mn; if(*z) z++; whatsup='hi'; k=0; };
- };
- if ( (z==rll+10000) || (i+j==len) )
- { m=z-rll;
- err = FSWrite ( tapeID, &m, rll );
- if (err) return ErrMsg("\p(FSWrite)");
- z=rll;
- };
- };
-
- RefreshWindows();
- }
-
- }
-
-
- // ----- record new sound to file and then open & convert this file
- //
- HandleNEW()
- { OSErr err; Point corner;
- StandardFileReply reply;
- long inRefNum;
- short channels;
- short sample_size;
- Fixed sample_rate; short i; Short n,m;
-
- ConMsg ( "\pRead data from tape","\pDaten von Kassette lesen" );
-
- if (german) StandardPutFile ( "\pName für die Sound-Zieldatei", "\pZXSpectrum .aiff", &reply );
- else StandardPutFile ( "\pName for the sound file", "\pZXSpectrum .aiff", &reply );
- if (!reply.sfGood) return ConMsg("\p*** Breaked ***","\p*** Abgebrochen ***");
- soundfile = reply.sfFile;
-
- ConPrint("\pDestination file: ","\pZieldatei: ");ConMsg(soundfile.name,0);
-
- if ( !reply.sfReplacing )
- { err = FSpCreate ( &soundfile, 'ZXSp', 'AIFF', 0 );
- if (err) return ErrMsg("\p(FSpCreate)");
- };
-
- err = FSpOpenDF ( &soundfile, fsCurPerm, &soundID );
- if (err=eofErr) err=noErr;
- if (err) soundID=0;
- if (err) return ErrMsg("\p(FSpOpenDF)");
-
- err = SPBOpenDevice ( "\p", siWritePermission, &inRefNum );
- if (!err)
- { err = SPBSetDeviceInfo ( inRefNum, 'plth', (Ptr)&plth_volume );
- if (err) ConMsg("\pSet play through volume failed",0);
-
- err = SPBSetDeviceInfo ( inRefNum, 'agc ', (Ptr)&auto_gain_control );
- if (err) ConMsg("\pSet automatic gain control failed",0);
-
- err = SPBGetDeviceInfo ( inRefNum, 'chan', (Ptr)&channels );
- if (err) ConMsg("\pGet number of channels failed",0);
- else
- { if (channels==1)
- { if (verbose==2) ConMsg("\pNumber of channels is mono",0);
- }
- else
- { if (verbose) ConMsg("\pSetting device to mono",0);
- channels=1;
- err = SPBSetDeviceInfo ( inRefNum, 'chan', (Ptr)&channels );
- if (err) ConMsg("\pSetting to mono failed",0);
- };
- };
-
- err = SPBGetDeviceInfo ( inRefNum, 'ssiz', (Ptr)&sample_size );
- if (err) ConMsg("\pGet sample size failed",0);
- else
- { if (sample_size==8)
- { if (verbose==2) ConMsg("\pSample size is 8 bit",0);
- }
- else
- { if (verbose) ConMsg("\pSetting sample size to 8 bit",0);
- sample_size=8;
- err = SPBSetDeviceInfo ( inRefNum, 'ssiz', (Ptr)&sample_size );
- if (err) ConMsg("\pFailed to set sample size",0);
- };
- };
-
- err = SPBGetDeviceInfo ( inRefNum, 'srat', (Ptr)&sample_rate );
- if (err) ConMsg("\pGet sample rate failed",0);
- else
- { if ((FixRound(sample_rate)>=21000) && (FixRound(sample_rate)<=23000))
- { if (verbose==2) ConMsg("\pSample rate is 22 kHz",0);
- }
- else
- { struct { short cnt; Fixed **table; } sample_rate_list;
-
- if (verbose) ConMsg("\pSetting sample rate to 22 kHz",0);
- err = SPBGetDeviceInfo ( inRefNum, 'srav', (Ptr)&sample_rate_list );
- if (err) ConMsg("\pGetting sample rate list failed",0);
- else
- { if (sample_rate_list.cnt)
- { if (verbose==2) ConMsg("\p[list of discrete sampling rates]",0);
- for (i=n=0;i<sample_rate_list.cnt;i++)
- { m=FixRound((*sample_rate_list.table)[i]);
- if (m<20050) n=m; else { if ((20050-n)<(m-20050)) m=n; break; };
- };
- sample_rate = Long2Fix(m);
- }
- else
- { if (verbose==2) ConMsg("\p[range of sampling rates]",0);
- sample_rate = Long2Fix(22000);
- };
- DisposHandle((Handle)sample_rate_list.table);
- err = SPBSetDeviceInfo ( inRefNum, 'srat', (Ptr)&sample_rate );
- if (err) ConMsg("\pFailed to set sample rate",0);
-
- err = SPBGetDeviceInfo ( inRefNum, 'srat', (Ptr)&sample_rate );
- if (err) ConMsg("\pGet sampling rate failed",0);
- else
- if ((FixRound(sample_rate)>=21000) && (FixRound(sample_rate)<=23000))
- { if (verbose==2) ConMsg("\pSample rate is 22 kHz",0);
- }
- else
- ConMsg("\pSample rate is •not• 22 kHz",0);
- };
- };
- };
-
- SPBCloseDevice ( inRefNum );
- }
- else ConMsg("\pFailed to initialize the sound input device","\pDer Toneingang konnte nicht parametriert werden");
-
- RefreshWindows();
- corner.v=40;
- corner.h=40;
- err = SndRecordToFile ( nil, corner, 'best', soundID );
- if (err)
- { CloseAll();
- if (err==userCanceledErr) return ConMsg("\p*** Breaked ***","\p*** Abgebrochen ***");
- else return ErrMsg("\p(SndRecordToFile)");
- };
-
- HandleOPEN ( soundfile );
- }
-
-
- // ============================================================================
- // ============================================================================
- // ============================================================================
- // ============================================================================
- // ============================================================================
-
-
- HandleSAVE() // save top window to disk
- { short n;
- n = Alert ( 128, nil );
- if (n==-1) ConMsg("\pResource 'ALRT' 128 is missing.","\pRessource 'ALRT' 128 fehlt.");
- }
-
- HandleKEYDOWN(Char key)
- {
- // 8 = Backspace 28 = Cursor left
- // 9 = Tab 29 = Cursor right
- // 13 = Return 30 = Cursor up
- // 31 = Cursor down
- }
-
- HandlePRINT() { } // print top window
-
- HandleACTIVATE() { } // window 'thePort' activated
- HandleDEACTIVATE() { } // window 'thePort' deactivated
- HandleINCONTENT() { } // in FrontWindow()
-
- HandleZOOMOUT() { } // in FrontWindow()
- HandleZOOMIN() { } // in FrontWindow()
- HandleGROW() { } // in FrontWindow()
-
- HandleUNDO() { } // 'Edit' menu
- HandleCUT() { } // 'Edit' menu
- HandleCOPY() { } // 'Edit' menu
- HandlePASTE() { } // 'Edit' menu
-
- // ***** not so often needed ***************************************
-
- HandleAUTOKEY(Char key) { HandleKEYDOWN(key); }
- HandleMOUSEUP() { }
- HandleKEYUP(Char key) { } // global event enabling needed !!
- HandleDISK() { } // Disk inserted (( ejected? ))
- HandleINDESK() { } // this should never happen
- HandleDRIVER() { } // used by system tasks only
- HandleAPP3() { } // application event
-
- HandleREGION() { } // mouse leaves 'eventRegion'
- HandleSUSPEND() { } // application is juggled out
- HandleRESUME() { } // application is juggled in
-
-