! test it ------------------------------------------------ GOSUB morseLib string2morse$ = "basic 4 ever " dit = 75 % [ms] frequency = 800 % [Hz] sound$ = morse$ ( string2morse$ ,dit ,frequency ,"", 1) CALL playInfinite ( sound$, string2morse$ , dit ) DO PAUSE 100 UNTIL0 END !--------------------------------------------- morseLib: FN.DEF playInfinite ( sound$, s2m$ , dit ) durationVec = charDurationVec ( s2m$ , dit ) LIST.TOARRAY durationVec, dur [] LIST.SIZE durationVec, sz DO AUDIO.STOP AUDIO.LOAD fi , sound$ AUDIO.PLAY fi IF fi > 1 THEN AUDIO.RELEASE fi-1 audioPosDes = 0 FOR i = 1 TO sz tmp $ = mid$(s2m$ , i, 1) PRINT format$("%%%",i);" | ";tmp$ ;" | "; getMorseCode$(tmp$) audioPosDes += dur[i] DO AUDIO.POSITION.CURRENT audioPos AUDIO.ISDONE audioIsdone UNTIL audioPos >= (audioPosDes-50) | audioIsdone NEXT UNTIL flagStop FN.END FN.DEF charDurationVec (s2s$, dit ) LIST.CREATE n, charDur FOR i = 1 TO LEN( s2s$ ) tmp$ = MID$( s2s$ , i, 1) IF !tmp$=" " mo$ = getMorseCode$ ( tmp$ ) tmp = 0 FOR j = 1 TO LEN(mo$) IF MID$(mo$,j,1)="." THEN tmp+=2*dit ELSE tmp+=4*dit NEXT LIST.ADD charDur, tmp +2*dit ELSE LIST.ADD charDur, 5*dit ENDIF NEXT LIST.SIZE charDur, sz FN.RTN charDur FN.END FN.DEF morse$ (s2s$, dit, frq, dat$, flagPr) s2s$ = LOWER$(s2s$) IF dat$="" THEN dat$ = REPLACE$(s2s$+".wav"," ","_") IF flagPr THEN print "---------------------" IF flagPr THEN print "creating morse-file: \"";dat$;"\"" IF flagPr THEN print sRate = 5500 dit = MIN(MAX(dit , 40) , 200 )/1000 frq = MIN(MAX(frq , 200), 2000) dah = 3*dit ton1$ = wavCreateToneData$ ( frq , dit ,sRate,1, 1) ton2$ = wavCreateToneData$ ( frq , dah ,sRate,1, 1) _pause$ = wavCreatePauseData$ ( dit ,sRate,1, 1) dit$ = ton1$ + _pause$ dah$ = ton2$ + _pause$ ple$ = _pause$ + _pause$ pwo$ = ple$ + ple$ + _pause$ FOR i = 1 TO LEN( s2s$ ) tmp$ = MID$( s2s$ , i, 1) IF !tmp$=" " mo$ = getMorseCode$ ( tmp$ ) FOR j = 1 TO LEN(mo $) IF MID$(mo$,j,1)="." THEN add$=dit$ ELSE add$=dah$ all$ = all$ + add$ NEXT all$ = all$ +ple$ ELSE all$ = all$ + pwo$ mo$ = " " ENDIF IF flagPr THEN print " "; tmp$; " "; mo$ NEXT IF flagPr THEN print IF flagPr THEN print "size sound data: " ; INT$(LEN(all$)) ; " [bytes]" header$ = wavCreateHeader$(sRate,LEN(all$),1,1) IF flagPr THEN print "writing sound data to file, please wait .... tic = clock () BYTE.OPEN w, fid, dat$ BYTE.WRITE.BUFFER fid, header$ + all$ BYTE.CLOSE fid dt = clock ()-tic IF flagPr THEN print "...done in: "; INT$(dt); "[ms] ("; ROUND((LEN(all$))/1.024/dt, 1) ; "[kb/s])" IF flagPr THEN print "---------------------" IF flagPr THEN print FN.RTN dat$ FN.END FN.DEF wavCreateToneData$ (frq, duration ,sampRate, nChan, nBitPerSamp) _2pi_frq = 2 * 3.14159 * frq dt = 1 / sampRate ampliCent = ROUND( 2^(nBitPerSamp*8) / 2 ) - 1 amplitude = ampliCent +1.000000001 FOR t = 0 TO duration STEP dt out$ = out$ + CHR$(amplitude*SIN(_2pi_frq*t) +ampliCent) NEXT FN.RTN out$ FN.END FN.DEF wavCreatePauseData$(duration ,sampRate, nChan, nBitPerSamp) nsamp = round ( sampRate * duration ) + 1 dt = 1 / sampRate samp$ = CHR$( ROUND( 2^(nBitPerSamp*8) / 2 ) -1) FOR t = 0 TO duration STEP dt out$ = out $ + samp$ NEXT FN.RTN out$ FN.END FN.DEF wavCreateHeader$(sampRate,nSamp,nChan,nBitPerSamp) nDatabytes = nSamp*nChan*nBitPerSamp byteRate = sampRate*nChan*nBitPerSamp DIM h$ [15] h$[1] = "RIFF" h$[2] = long2Str$( nDatabytes +36 ) h$[3] = "WAVE" h$[4] = "fmt " h$[5] = long2Str$( 16 ) h$[6] = word2Str$( 1 ) h$[7] = word2Str$( nChan ) h$[8] = long2Str$( sampRate ) h$[9] = long2Str$( byteRate ) h$[10] = word2Str$( nChan*nBitPerSamp ) h$[11] = word2Str$( nBitPerSamp*8 ) h$[12] = "data" h$[13] = long2Str$( nDatabytes ) FOR i = 1 TO 13 header$ = header$ + h$ [i] NEXT FN.RTN header$ FN.END FN.DEF getMorseCode$ (character$) if character$ = " " then fn.rtn " " morse$ = ~ "a.- , b-... , c-.-. , d-.. , e. , f..-. , g--. , h.... , i.. ,j.--- , k-.- , l.-.. , m-- , n-. , o--- , p.--. , q--.- , r.-. ,s... , t- , u..- , v...- , w.-- , x-..- , y-.-- , z-.. , 0----- , 1.---- , 2..--- , 3...-- , 4 ....- , 5 ..... , 6-.... , 7--... , 8---.. , 9 ----." morse$ = REPLACE$( morse$," ","") pos1 = IS_IN( character$ , morse$ , 1) + 1 pos2 = IS_IN( "," , morse$ , pos1) FN.RTN mid$ (morse$, pos1, pos2- pos1) FN.RTN FN.END FN.DEF long2Str$( val ) FN.RTN CHR$(val)+CHR$(val/2^8)+CHR$(val/2^16)+CHR$(val/2^24) FN.END FN.DEF word2Str$( val ) FN.RTN CHR$(val)+CHR$(val/2^8) FN.END RETURN !--------------------------------------------- !! infos ---------------------------------------- link: https://ccrma.stanford.edu/courses/422/projects/WaveFormat/ 0 4 ChunkID Contains the letters "RIFF" in ASCII form 4 4 ChunkSize 36 + SubChunk2Size, or more precisely: 4 + (8+SubChunk1Size) + (8+SubChunk2Size) This is the size of the rest of the chunk following this number. This is the size of the entire file in bytes minus 8 bytes for the two fields not included in this count: ChunkID and ChunkSize. 8 4 Format Contains the letters "WAVE" The "WAVE" format consists of two subchunks"fmt " and "data": The "fmt " subchunk describes the sound data's format: 12 4 Subchunk1ID Contains the letters "fmt " 16 4 Subchunk1Size 16 for PCM. This is the size of the rest of the Subchunk which follows this number. 20 2 AudioFormat PCM = 1 (i.e. Linear quantization) Values other than 1 indicate some form of compression. 22 2 NumChannels Mono = 1, Stereo = 2, etc. 24 4 SampleRate 8000, 44100, etc. 28 4 ByteRate == SampleRate * NumChannels * BitsPerSample/8 32 2 BlockAlign == NumChannels * BitsPerSample/8 The number of bytes for one sample including all channels. I wonder what happens when this number isn't an integer? 34 2 BitsPerSample 8 bits = 8, 16 bits = 16, etc. 36 4 Subchunk2ID Contains the letters "data" 40 4 Subchunk2Size == NumSamples * NumChannels * BitsPerSample/8 This is the number of bytes in the data. You can also think of this as the size of the read of the subchunk following this number. 44 * Data The actual sound data. !----------------------------------------------- !!