Building Spectrum emulatorCompiling:ZXio.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)3 passes, 11429 bytes.Compiling:Z80.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 279826 bytes.Compiling:video.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)3 passes, 5916 bytes.Compiling:videoMemory.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)3 passes, 9359 bytes.Compiling:OO.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 143179 bytes.Compiling:CB.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 107153 bytes.Compiling:ED.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 39351 bytes.Compiling:DD.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 46811 bytes.Compiling:FD.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 55618 bytes.Compiling:DDCB.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 114656 bytes.Compiling:FDCB.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 159967 bytes.Compiling:Spectrum emulator.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)3 passes, 61839 bytes.Linking:Spectrum emulator.exeExecuting:Spectrum emulator.exestart ADDRESSPEEK(33902)=80PEEK(33903)=128PEEK(33904)=129PEEK(33905)=80PEEK(33906)=102PEEK(33907)=103PEEK(33908)=80PEEK(33909)=86PEEK(33910)=87PEEK(33911)=50PEEK(33912)=86PEEK(33913)=87PEEK(33914)=50PEEK(33915)=171PEEK(33916)=203PEEK(33917)=50PEEK(33918)=43PEEK(33919)=51PEEK(33920)=50PEEK(33921)=43PEEK(33922)=51PEEK(33923)=50PEEK(33924)=171PEEK(33925)=203PEEK(33926)=50PEEK(33927)=51PEEK(33928)=64PEEK(33929)=50PEEK(33930)=51PEEK(33931)=64PEEK(33932)=50PEEK(33933)=171PEEK(33934)=203PEEK(33935)=50PEEK(33936)=128PEEK(33937)=129PEEK(33938)=50PEEK(33939)=128PEEK(33940)=129PEEK(33941)=50PEEK(33942)=102PEEK(33943)=103PEEK(33944)=50PEEK(33945)=86PEEK(33946)=87PEEK(33947)=50PEEK(33948)=96PEEK(33949)=86PEEK(33950)=50PEEK(33951)=171PEEK(33952)=192PEEK(33953)=50PEEK(33954)=43PEEK(33955)=48PEEK(33956)=50PEEK(33957)=43PEEK(33958)=48PEEK(33959)=50PEEK(33960)=171PEEK(33961)=192PEEK(33962)=50PEEK(33963)=48PEEK(33964)=68PEEK(33965)=50PEEK(33966)=48PEEK(33967)=68PEEK(33968)=50PEEK(33969)=171PEEK(33970)=192PEEK(33971)=50PEEK(33972)=136PEEK(33973)=137PEEK(33974)=50PEEK(33975)=136PEEK(33976)=137PEEK(33977)=50PEEK(33978)=114PEEK(33979)=115PEEK(33980)=50PEEK(33981)=76PEEK(33982)=77PEEK(33983)=50PEEK(33984)=76PEEK(33985)=77PEEK(33986)=50PEEK(33987)=171PEEK(33988)=192PEEK(33989)=50PEEK(33990)=38PEEK(33991)=48PEEK(33992)=50PEEK(33993)=38PEEK(33994)=48PEEK(33995)=50PEEK(33996)=171PEEK(33997)=192PEEK(33998)=50PEEK(33999)=48PEEK(34000)=68PEEK(34001)=50PEEK(34002)=48PEEK(34003)=68PEEK(34004)=50PEEK(34005)=171PEEK(34006)=192PEEK(34007)=50PEEK(34008)=136PEEK(34009)=137PEEK(34010)=50PEEK(34011)=136PEEK(34012)=137PEEK(34013)=50PEEK(34014)=114PEEK(34015)=115PEEK(34016)=50PEEK(34017)=76PEEK(34018)=77PEEK(34019)=50PEEK(34020)=76PEEK(34021)=77PEEK(34022)=50PEEK(34023)=171PEEK(34024)=203PEEK(34025)=50PEEK(34026)=38PEEK(34027)=51PEEK(34028)=50PEEK(34029)=38PEEK(34030)=51PEEK(34031)=50PEEK(34032)=171PEEK(34033)=203PEEK(34034)=50PEEK(34035)=51PEEK(34036)=64PEEK(34037)=50PEEK(34038)=51PEEK(34039)=64PEEK(34040)=50PEEK(34041)=171PEEK(34042)=203PEEK(34043)=50PEEK(34044)=128PEEK(34045)=129PEEK(34046)=50PEEK(34047)=128PEEK(34048)=129PEEK(34049)=50PEEK(34050)=102PEEK(34051)=103PEEK(34052)=50PEEK(34053)=86PEEK(34054)=87PEEK(34055)=50PEEK(34056)=64PEEK(34057)=65PEEK(34058)=50PEEK(34059)=128PEEK(34060)=171PEEK(34061)=50PEEK(34062)=32PEEK(34063)=43PEEK(34064)=50PEEK(34065)=32PEEK(34066)=43PEEK(34067)=50PEEK(34068)=128PEEK(34069)=171PEEK(34070)=50PEEK(34071)=43PEEK(34072)=51PEEK(34073)=50PEEK(34074)=43PEEK(34075)=51PEEK(34076)=50PEEK(34077)=128PEEK(34078)=171PEEK(34079)=50PEEK(34080)=128PEEK(34081)=129PEEK(34082)=50PEEK(34083)=128PEEK(34084)=129PEEK(34085)=50PEEK(34086)=102PEEK(34087)=103PEEK(34088)=50PEEK(34089)=86PEEK(34090)=87PEEK(34091)=50PEEK(34092)=64PEEK(34093)=65PEEK(34094)=50PEEK(34095)=128PEEK(34096)=152PEEK(34097)=50PEEK(34098)=32PEEK(34099)=38PEEK(34100)=50PEEK(34101)=32PEEK(34102)=38PEEK(34103)=50PEEK(34104)=128PEEK(34105)=152PEEK(34106)=50PEEK(34107)=38PEEK(34108)=48PEEK(34109)=50PEEK(34110)=38PEEK(34111)=48PEEK(34112)=50PEEK(34113)=0PEEK(34114)=0PEEK(34115)=50PEEK(34116)=114PEEK(34117)=115PEEK(34118)=50PEEK(34119)=114PEEK(34120)=115PEEK(34121)=50PEEK(34122)=96PEEK(34123)=97PEEK(34124)=50PEEK(34125)=76PEEK(34126)=77PEEK(34127)=50PEEK(34128)=76PEEK(34129)=153PEEK(34130)=50PEEK(34131)=76PEEK(34132)=77PEEK(34133)=50PEEK(34134)=76PEEK(34135)=77PEEK(34136)=50PEEK(34137)=76PEEK(34138)=153PEEK(34139)=50PEEK(34140)=91PEEK(34141)=92PEEK(34142)=50PEEK(34143)=86PEEK(34144)=87PEEK(34145)=50PEEK(34146)=51PEEK(34147)=205PEEK(34148)=50PEEK(34149)=51PEEK(34150)=52PEEK(34151)=50PEEK(34152)=51PEEK(34153)=52PEEK(34154)=50PEEK(34155)=51PEEK(34156)=205PEEK(34157)=50PEEK(34158)=64PEEK(34159)=65PEEK(34160)=50PEEK(34161)=102PEEK(34162)=103PEEK(34163)=100PEEK(34164)=102PEEK(34165)=103PEEK(34166)=50PEEK(34167)=114PEEK(34168)=115PEEK(34169)=100PEEK(34170)=76PEEK(34171)=77PEEK(34172)=50PEEK(34173)=86PEEK(34174)=87PEEK(34175)=50PEEK(34176)=128PEEK(34177)=203PEEK(34178)=25PEEK(34179)=128PEEK(34180)=0PEEK(34181)=25PEEK(34182)=128PEEK(34183)=129PEEK(34184)=50PEEK(34185)=128PEEK(34186)=203PEEK(34187)=255end ADDRESS
Building Spectrum emulatorCompiling:ZXio.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)3 passes, 11429 bytes.Compiling:Z80.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 279855 bytes.Compiling:video.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)3 passes, 5916 bytes.Compiling:videoMemory.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)3 passes, 9359 bytes.Compiling:OO.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 143179 bytes.Compiling:CB.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 107153 bytes.Compiling:ED.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 39351 bytes.Compiling:DD.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 46811 bytes.Compiling:FD.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 55618 bytes.Compiling:DDCB.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 114656 bytes.Compiling:FDCB.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)4 passes, 159967 bytes.Compiling:Spectrum emulator.bmxflat assembler version 1.69.14 (1572863 kilobytes memory)3 passes, 61839 bytes.Linking:Spectrum emulator.exeExecuting:Spectrum emulator.exeStart ADDRESS 3390280,128,129,80,102,103,80,86,87,50,86,87,50,171,203,50,43,51,50,43,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,96,86,50,171,192,50,43,48,50,43,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,192,50,38,48,50,38,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,203,50,38,51,50,38,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,171,50,32,43,50,32,43,50,128,171,50,43,51,50,43,51,50,128,171,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,152,50,32,38,50,32,38,50,128,152,50,38,48,50,38,48,50,0,0,50,114,115,50,114,115,50,96,97,50,76,77,50,76,153,50,76,77,50,76,77,50,76,153,50,91,92,50,86,87,50,51,205,50,51,52,50,51,52,50,51,205,50,64,65,50,102,103,100,102,103,50,114,115,100,76,77,50,86,87,50,128,203,25,128,0,25,128,129,50,128,203,255End ADDRESS 34187
Cool, we are getting there.Because the frequency is not actually passed to the speaker; I have been playing around with how we get the timings for the audio and come up with a way that counts the duration between calls to OUT(254,A) and then generates an audio sample to match the frequency of the calls The idea is that your Emulator will be running at the same speed as the ZX Spectrum 48K (3.500MHz), so the "pulses" to the Speaker should match the frequency we need to make the correct sound. The note values in the data appear to have been calculated relative to the Spectrum CPU speed and the TStates of the music code loop which is why the values do not match the desired frequency. My first run-through made a series of strange crackles, so I have a bit of work to do, but will post when I have ironed out a few bugs.
Have a look at QasarBeachhttps://adamstrange.itch.io/qasarbeachIt will allow you to visualize any kind of waveform - allow you to draw waveforms, etc and view/hear the results in realtime.You can also create sounds, load sounds and generally bugger them up to your hearts content.Sound theory is simple, but doing it in realtime over multiple voices is more of a challenge, but I'll help where you need it
the simple way is to create a single sample say 128frames in lengthfill this with a square wave (< 64 sample=-1 > 64 sample =1)play this as a sound with a loop - thats your baseplay the sound through a channel to allow for direct manipulationuse pitch, pan, vol to do all the other stuff <-these are channel controlsSpectrum only used square waves
SuperStrict' Simple Square Wave Player' Create a BuzzerAppTitle = "BUZZER.1"Global buzzer:TChannel = CreateBuzzer()' Create one "wave" of the supplied frequencyFunction CreateBuzzer:TChannel() Const amplitude:Float= 1.0 ' Volume 0.0 to 1.0 Const frequency:Int = 261.63 'Hz = C4 = Middle-C Const samplerate:Int = 44000 Local sample:TAudioSample = CreateAudioSample( frequency, 44000, SF_MONO8 ) Print( "Sample length "+sample.length ) Local half:Float = frequency/2.0 For Local n:Int = 0 Until sample.length Local level:Float = n Mod frequency If level<half sample.samples[n] = amplitude Else sample.samples[n] = -amplitude EndIf Next ' Cue a buzz sound ready to be played Return CueSound( LoadSound( sample, True ) ) End FunctionLocal state:Int = False, rate:Float = 1.0Local text:String Graphics 200,50Repeat Cls text = "SPACE = ON/OFF" DrawText( text,(GraphicsWidth()-TextWidth(text))/2,(GraphicsHeight()-TextHeight(text))/3 ) text = "UP/DOWN = PITCH" DrawText( text,(GraphicsWidth()-TextWidth(text))/2,(GraphicsHeight()-TextHeight(text))/3*2 ) If KeyHit( KEY_SPACE ) state = Not state If state buzzer.setpaused( False ) Else buzzer.setpaused( True ) EndIf EndIf If KeyHit( KEY_UP ) rate :+ 0.1 buzzer.setrate( rate ) EndIf If KeyHit( KEY_DOWN) rate :- 0.1 buzzer.setrate( rate ) EndIf FlipUntil KeyHit( KEY_ESCAPE )
' CreateSquareWave'SuperStrictGraphics 640,480' Higher the Duration the BASSier Tone isGlobal Duration:Byte=128 ' Or total samples per One Cycle' Max Frequency for Ear so dosent need to be higher!?' However the Lower it is the duller or Bassier sound we get. Const SamplesPerSecond:Float=22000 'Global Hertz:Float=HumanEarMAXGlobal AudioSample:TAudioSample=CreateAudioSample( duration, SamplesPerSecond, SF_MONO8 )Function OUT_Piezo_(Duration:Byte, Hertz:Short) AudioSample:TAudioSample=CreateAudioSample( Length, SamplesPerSecond, SF_MONO8 ) For Local K:Float=0 Until Duration ' ZX Spectrum could only play a Square Wave ' So a Work around For a very crude Square Wave! If K<(Duration/2) Then AudioSample.samples[K] = 1 Else AudioSample.samples[K] = 0 NextEnd FunctionGlobal audio:TSound=LoadSound( AudioSample, True )channel=CueSound(audio)While Not (AppTerminate() Or KeyDown(key_space))If MouseHit(1) PlaySound audio,channelLocal Pan# = MouseX () / (GraphicsWidth () / 2.0) Local Vol# = 1 - (MouseY () *.0023)Local Rate#=Pan#' Not needed for Specy, As it was always MONO! But Pan#=0 for CENTER'Pan#=0 ; SetChannelPan channel,0 ' Turning Piezo ON/OFF Vol=0 for OFF and Vol=1 for ONSetChannelVolume channel,Vol#SetChannelRate channel,rate#'StopChannel channel'Audiosample.length=Duration'Audiosample.hertz=hertz'Hertz=Rnd (0.0, 44000)'OUT_Piezo_(Duration,Hertz)Cls DrawText "Left Click to Play", 240, 200 DrawText "Pan : " + pan, 240, 220 DrawText "Volume: " + vol, 240, 240 FlipWend
#include "time.h"#include <sys/time.h>long MicroSecs(void) { struct timeval tv; gettimeofday( &tv, NULL ); return (( (long)tv.tv_sec )*1000000 )+( tv.tv_usec );}
Import "microsecs.c"Extern Function MicroSecs:Long()EndExtern
Function _OUT( port:Byte, value:Byte) Global savestate:Int=False Global savetime:Long, counter:Int If port=254 Local speaker:Int = (value&$10) counter :+ 1 If speaker = savestate Return ' State has not changed Local now:Long = MicroSecs() If speaker ' Speaker turned ON, play last wave Local duration:Long = now-savetime duration = Min(duration,500) ' Allow for clock creep'Print( "- duration: "+duration+" us" ) Print( "CREATE SAMPLE "+counter+", "+ duration+"us") savetime = now counter = 0 End If savestate = speaker End IfEnd Function
All values are INTEGER!!!To create a Square-Signal the both values are 0 and 255!!! 128 is the Zero-Signal255 is full positiv +1270 is full negativ -128
The Hertz is the Frequency to alter from 0 to 255
SuperStrict' Manic Miner Audio OutputImport "microsecs.c"Extern Function MicroSecs:Long()EndExtern' ZX Spectrum 16K/48K = 3.500 Mhz' ZX Spectrum 128K = 3.547 MhzConst CLOCKSPEED:Float = 3.500 'MhzConst __CPUCYCLE__:Float = (1.0/(CLOCKSPEED)) 'in MicrosecondsPrint( "1 Cycle = "+(__CPUCYCLE__)+" microseconds")Print( "108 Cycles= "+(__CPUCYCLE__*108)+" microseconds")' 16 Bit RegsitersGlobal BC16:ShortGlobal DE16:ShortGlobal HL16:ShortGlobal BC:Byte Ptr = Varptr BC16Global DE:Byte Ptr = Varptr DE16Global HL:Byte Ptr = Varptr HL16Const B:Byte=1, C:Byte=0, D:Byte=1, E:Byte=0, H:Byte=1, L:Byte=0' 8 Bit RegistersGlobal A:ByteGlobal IY:Byte, IX:Byte' FLAGSGlobal F:Byte[8]Const CF:Byte=0Const ZR:Byte=1' Music DataGlobal data:Byte[] = [80,128,129,80,102,103,80,86,87,50,86,87,50,171,203,50,43,51,50,43,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,96,86,50,171,192,50,43,48,50,43,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,192,50,38,48,50,38,48,50,171,192,50,48,68,50,48,68,50,171,192,50,136,137,50,136,137,50,114,115,50,76,77,50,76,77,50,171,203,50,38,51,50,38,51,50,171,203,50,51,64,50,51,64,50,171,203,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,171,50,32,43,50,32,43,50,128,171,50,43,51,50,43,51,50,128,171,50,128,129,50,128,129,50,102,103,50,86,87,50,64,65,50,128,152,50,32,38,50,32,38,50,128,152,50,38,48,50,38,48,50,0,0,50,114,115,50,114,115,50,96,97,50,76,77,50,76,153,50,76,77,50,76,77,50,76,153,50,91,92,50,86,87,50,51,205,50,51,52,50,51,52,50,51,205,50,64,65,50,102,103,100,102,103,50,114,115,100,76,77,50,86,87,50,128,203,25,128,0,25,128,129,50,128,203,255]' Direct Code ConversionFunction CALL_37596:Int()Local __TSTATES__:Int While True A = data[IY] '37596 LD A,(IY+0) Pick up the next byte of tune data from the table at 33902 If A=255 '37599 CP 255 Has the tune finished? Return True '37601 RET Z Return (with the zero flag set) if so End If BC[C] = A '37602 LD C,A Copy the first byte of data for this note (which determines the duration) to C BC[B] = 0 '37603 LD B,0 Initialise B, which will be used as a delay counter in the note-producing loop A = 0 '37605 XOR A Set A=0 (for no apparent reasaon) DE[D] = data[IY+1] '37606 LD D,(IY+1) Pick up the second byte of data for this note '##### UPDATE AN ONSCREEN KEYBOARD TO SHOW NOTE 'A = DE[D] '37609 LD A,D Copy it to A 'CALL_37675() '37610 CALL 37675 Calculate the attribute file address for the corresponding piano key 'mem(HL,80) '37613 LD (HL),80 Set the attribute byte for the piano key to 80 (INK 0: PAPER 2: BRIGHT 1) DE[E] = data[IY+2] '37615 LD E,(IY+2) Pick up the third byte of data for this note '##### UPDATE AN ONSCREEN KEYBOARD TO SHOW NOTE 'A = DE[E] '37618 LD A,E Copy it to A 'CALL_37675() '37619 CALL 37675 Calculate the attribute file address for the corresponding piano key 'mem(HL,40) '37622 LD (HL),40 Set the attribute byte for the piano key to 40 (INK 0: PAPER 5: BRIGHT 0)'Print( "A ---"+Right(Hex(A),2)+" BC-"+Right(Hex(BC16),4)+" DE-"+Right(Hex(DE16),4)+" HL-"+Right(Hex(HL16),4) ) Repeat ' until C=0 (at 37645) Repeat ' until B=0 (at 37642) _OUT(254,A) '37624 OUT (254),A Produce a sound based on the frequency parameters in the second and third bytes of data for this note (copied into D and E) __TSTATES__ = 0 DE[D] :- 1 '37626 DEC D If DE[D]=0 '37627 JR NZ,37634 DE[D] = data[IY+1] '37629 LD D,(IY+1) A = A~24 '37632 XOR 24 __TSTATES__ :+ 26 End If DE[E] :- 1 '37634 DEC E If DE[E]=0 '37635 JR NZ,37642 DE[E] = data[IY+2] '37637 LD E,(IY+2) A = A~24 '37640 XOR 24 __TSTATES__ :+ 26 End If BC[B] :- 1 '37642 DJNZ 37624 ' SLOW DOWN BLITZMAX SO CODE RUNS AT SAME SPEED AS ZX SPECTRUM __TSTATES__ :+ 56 'Print(microsecs()) Local wait:Long = MicroSecs()+Long(__TSTATES__*__CPUCYCLE__) 'Print("wait "+wait) 'Print("tstates "+__TSTATES__) While wait>MicroSecs() ; Wend 'Print( "A ---"+Right(Hex(A),2)+" BC-"+Right(Hex(BC16),4)+" DE-"+Right(Hex(DE16),4)+" HL-"+Right(Hex(HL16),4) ) Until BC[B]=0 ' "" "" BC[C] :- 1 '37644 DEC C Until C=0 '37645 JR NZ,37624 '##### KEYBOARD INTERACTION 'If CALL_37687() '37647 CALL 37687 Check whether ENTER or the fire button is being pressed ' Return False '37650 RET NZ Return (with the zero flag reset) if it is 'End If '##### UPDATE AN ONSCREEN KEYBOARD TO SHOW NOTE 'A = data[IY+1] '37651 LD A,(IY+1) Pick up the second byte of data for this note 'CALL_37675() '37654 CALL 37675 Calculate the attribute file address for the corresponding piano key 'mem(HL,56) '37657 LD (HL),56 Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0) '##### UPDATE AN ONSCREEN KEYBOARD TO SHOW NOTE 'A = data[IY+2] '37659 LD A,(IY+2) Pick up the third byte of data for this note 'CALL_37675() '37662 CALL 37675 Calculate the attribute file address for the corresponding piano key 'mem(HL,56) '37665 LD (HL),56 Set the attribute byte for the piano key back to 56 (INK 0: PAPER 7: BRIGHT 0) IY :+ 3 '37667 INC IY Move IY along to the data for the next note in the tune '37669 INC IY '37671 INC IY Wend '37673 JR 37596 Jump back to play the next noteEnd Function' Direct Code Conversion' Calculates which on-screen piano key will be shown pressed' We dont need this, so it has been commented out'Function CALL_37675()' A :- 8 '37675 SUB 8 Compute the piano key index (K) based on the frequency parameter (F), and store it in bits 0-4 of A: K=31-INT((F-8)/8)' _RRCA() '37677 RRCA' _RRCA() '37678 RRCA' _RRCA() '37679 RRCA' A = ~A '37680 CPL ' A :| 224 '37681 OR 224 A=224+K; this is the LSB' HL[L] = A '37683 LD L,A Set HL to the attribute file address for the piano key' HL[H] = 89 '37684 LD H,89' Return '37686 RET'End Function' Keyboard input' Not required, so has been commented out'Function CALL_37687:Int()' Return False'End Function' Z80 Mnumonic Rotate Bits Right with Carry'Function _RRCA()' Local x:Byte = A & $01' A = ( A Shr 1 | ( A & $01 ) Shl 7 )' F[CF] = x'End Function' Z80 Mnumonic' bitmap of value is xxxSMBBB' S=Sound M=Microphone B=BorderFunction _OUT( port:Byte, value:Byte) Global savestate:Int=False Global savetime:Long, counter:Int If port=254 Local speaker:Int = (value&$10) counter :+ 1 If speaker = savestate Return ' State has not changed Local now:Long = MicroSecs() If speaker ' Speaker turned ON, play last wave Local duration:Int = now-savetime duration = Min(duration,500)*10'Print( "- duration: "+duration+" us" ) Print( "CREATE SAMPLE "+counter+" Hz, "+ duration) Buzz( duration, counter ) savetime = now counter = 0 End If savestate = speaker End IfEnd Function' Create one "wave" of the supplied frequencyFunction Buzz:TChannel( duration:Int, frequency:Int ) 'Const amplitude:Float= 1.0 ' Volume 0.0 to 1.0 'Const frequency:Int = 261.63 'Hz = C4 = Middle-C Const SAMPLERATE:Int = 11025 Local sample:TAudioSample = CreateAudioSample( duration, SAMPLERATE, SF_MONO8 ) Local half:Int = frequency/2 Local w% For Local n:Int=0 Until sample.length -1 w=w+1 If (w Mod frequency)< half sample.samples[n] = 255 Else sample.samples[n] = 0 EndIf Next Local audio:TSound = LoadSound( sample ) PlaySound( audio ) End Function' Play MusicPrint( "Starting" )IY = 0 ' Set pointer to start of musicCALL_37596()
To use it, simply add this to the top of your Blitzmax code:microsecs.cCode: [Select]#include "time.h"#include <sys/time.h>long MicroSecs(void) { struct timeval tv; gettimeofday( &tv, NULL ); return (( (long)tv.tv_sec )*1000000 )+( tv.tv_usec );}Code: [Select]Import "microsecs.c"Extern Function MicroSecs:Long()EndExternHi Si, Not interfaced with C before. Ive worked out you use the C snipet of your code and save as microsecs.c file. Ive saved it the local directory and in BlitzMax tmp folder.Ive then used the 2nd piece of code to import "microsecs.C". But when i compile i get the following.Code: [Select]Building Import microsecsCompiling:microsecs.cBuild Error: failed to compile C:/Spectrum7/Sound Stuff/microsecs.cProcess completeI think i need to do something else but i dunno what. Kind Regards Baggey
Building Import microsecsCompiling:microsecs.cBuild Error: failed to compile C:/Spectrum7/Sound Stuff/microsecs.cProcess complete
Const ClockSpeedDOUBLE:Double = 3.5*10^6 ' ie, 3500000 or ( 3.5 EXP 6 Calculator )Const ClockSpeedFLOAT:Float = 3.5*10^6 ' ie, 3500000 or ( 3.5 EXP 6 Calculator )Const ClockSpeed=3500000Const Z80_CPU_Cycle:Float=0.000000285 ' Cycles per second. Most instructions take a minimum of 4 TStatesGlobal OpCode_Time:FloatPrintPrint "ClockSpeed as a DOUBLE="+ClockSpeedDOUBLEPrintPrint " Or"PrintPrint "ClockSpeed as a FLOAT="+ClockSpeedFLOATPrintPrintPrint "BLITZ MAX Dosen't make the numbers nice!"PrintPrint " Clock Speed is = "+ClockSpeed+" Hz ... Maybe more familiar as 3,500,000 Hz or 3.5 Mhz"PrintPrint " Which is 3.5*10^6 or ( 3.5 EXP 6 Calculator )"Print PrintPrint " So, One Z80 CPU takes 1/3.5*10^6 or ( 1/3.5 EXP 6 Calulator )"Print "ie,"Print " One CPU cycle = 0.000000285 Secs ... 0.285 uSecs or micro Seconds ... 0.285*10^(-6) or ( 0.285 EXP -6 Calulator )"Print " Or 285 nSecs or nano Seconds ... 285*10^(-9) or ( 285 EXP -6 Calculator )"PrintPrint "So, Blitzmax notation "PrintConst __CPUCYCLE__:Float = (1/ClockSpeedFloat)Print " 1 CPU cycle = "+(__CPUCYCLE__)+" Which as i say isn't nice!"PrintPrint "or, Z80_CPU_Cycle = 0.000000285"PrintPrint "Therefore,"PrintPrint "108 Cycles= "+(__CPUCYCLE__*108)Print Print "Which is 0.000030857 Secs ... or 30.857uSecs micro Seconds ... 30.857*10^(-6) or ( 30.857 EXP -6 Calculator )"PrintPrint "Consider a NOP Instruction 4 Tstates"PrintPrint "4 Cycles= "+(__CPUCYCLE__*4)+" microseconds"PrintPrint "Which is 0.000001142 Secs ... or 1.142uSecs micro Seconds ... 1.142*10^(-6) or ( 1.142 EXP -6 Calculator )"PrintPrint "Anyone wishing to work out how many Seconds a TCycle takes, or instruction can take."Print "We can use the following Formulae"PrintPrint " Tstates of Instruction * 1 / 3.5*10^6 = Time Taken in Seconds"PrintPrint "ie, Our NOP Instruction has 4 * 1 / 3.5*10^6 = Time Taken in Seconds or BlitzMax Time Taken = 4*(1/(3.5*10^6))"PrintPrint "Time for NOP OpCode = "+4*(1/(3.5*10^6))+" ... Which is 1.142*10^6 Seconds"PrintPrint "Incidently the Brackets are there forcing a Mathamatical rule called BIDMAS. To make BlitzMax Enforce this RULE"Print "the Brackets are there. Meaning anything representing the letter is done first! or within the Brackets"Print "Otherwise are Sum is going to be wrong!"PrintPrint " B = Brackets"Print " I = Indicies"Print " D = Division"Print " M = Multiplication"Print " A = Addition"Print " S = Subtraction"Print " Time Taken to execute = Tstates for Instruction * (1/(3.5*10^6))"