![]() |
Forum Index : Microcontroller and PC projects : PicoMiteVGA: some Entertainer-ment and some bugs (?)
![]() ![]() ![]() ![]() |
|||||
Author | Message | ||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
You are just overdriving the audio PWM. PWM duty > PWM total. The firmware should protect against this but something isn't quite right - will look next week |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5090 |
Tom, Peter is right. You are overdriving the PWM. On PicomiteVGA 5.07.05b6 What happens is that all the tones you want to play are numerically added and then send to the PWM. 2 tones exactly fill the PWM range, but the 3'rd and forth make the audio clip (distortion). You have to use the "volume" setting that comes with the play sound command (not the generic volume setting (play volume l,r) but the volume in the play command) play sound 1,b,s,500,25 play sound 2,b,s,550,25 play sound 3,b,s,600,25 Works fine. The 25 is the max volume setting. For some reason, if you do not set the volume you get distortion. But when you set the volume to it's maximum (25) you get no distortion. After some testing with only 1 channel I can conclude that the default volume setting Peter uses is 50. And the maximum you can set is 25. Volhout P.S. if you want I can post oscilloscope graphs, but they are photo's (not very crisp). Edited 2022-06-09 04:34 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Thanks folks, that makes sense. Volhout, if you have time then couple of those plus some commentary would do my education no harm. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5090 |
Oh Tom, Here you go. This first picture is a single tone (play sound 1,b,s,500). Each horizontal grid line on screen is 0.5V, so the amplitude of the sinewave is 3.2 x 0.5 = 1.6V. ![]() When you add the second tone (play sound 2,b,s,550) the signal is added to the first. If you add up 2 sinewaves with different frequency there will be moments in time where the voltage is summed up, but in other moments the 2 cancel eachother out. (you can try on MMBasic by drawing a graph of 2 added sinewaves with different frequency) ![]() In this graph you can see that the sum of both sinewaves has an amplitude of over 3V. And this is generated by the PWM on the output pin of the pico. This pin has only 0V and 3.3V levels. So it is at it's max. The next waveform is what happens if you add a 3'rd sine wave. (play sound 3,b,s,600) The signals sum up to 4.5V, and the pin can only drive 3.3V. What happens is that you get a numerical "wrap around" for +3.3V to 0V. You can clearly see that in the right side of this (zoomed in) waveform. At some point the signal is clipping at 3.3V, and at some point there is a wrap around to 0V. This is an immense distortion that sounds like chirps, with a repetition rate of few Hz. If you add a 4'th it is only getting worse. ![]() Please note that the waveforms will not look as nice as these on your VGA pico GAME board. My picomiteVGA has a better 44kHz filter (sampling rate of the audio), so the PWM frequency is almost invisible in the waveform. There was a discussion on that in the VGA pico GAME board thread. Edited 2022-06-09 07:14 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Thanks @Volhout, Something is confusing me though, in the first plot if the horizontal lines are at 500mV intervals then it looks like the peak-to-peak voltage is ~1.6V, doesn't that make the amplitude ~0.8V ? Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
phil99![]() Guru ![]() Joined: 11/02/2018 Location: AustraliaPosts: 2642 |
After a DC blocking capacitor the peak amplitude is 0.8V but for clipping of the PWM signal the Peak-to-Peak amplitude is what matters. |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5090 |
Hi Tom, There are several ways to define the amplitude. Most common are - peak to peak voltage - rms voltage (for a sine wave that is 1/(2*sqrt(2)) of peak to peak) And you are right: the "amplitude" is indeed 0.8V (according WIKIPEDIA) To avoid confusion I mostly add a suffix. This case I did not.... For this sine wave: Vp would be the 0.8V Vpp would be 1.6V Vrms would be 0.57V Edited 2022-06-11 00:01 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
In this case it's Vpp that matters because you are interested in clipping (and it's usually easier to think Vpp on a scope anyway). Nice scopes will display the RMS as well, but not all will do that - you have to work it out if you need it. Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Thanks, I guess the amplitude I remember from A-Level physics was the one corresponding to Vp, hence my confusion. Anyway it's all ~good now. I'll post a 3-channel PicoMite rendition of The Entertainer when I get a moment over the weekend - it's for the game I promised Mick for the PicoGAME and am still plugging away at. Best wishes, Tom MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10315 |
Volhout Please can you post the latest version of your audio filter. I would like to incorporate it in a new version of the VGA PCB. Thanks |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
Oddly enough, I've just added the version I used for the keyboard pcb to the PicoGAME today. :) Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5090 |
Hi Peter, The filter I reworked on my version of the PicomiteVGA board (your layout) is this: ![]() Theoretically the 5.6nF capacitor should be 6.2nF, but that value is hard to get. If you have sufficient place on the board you could parallel layout 4.7nF and 1.5nF. But board area will be difficult anyway, since the inductors are like large resistors. The 35 ohm resistor is internal in the inductor (wire resistance), so it is not a separate component. The BOM would be: 2.2mH inductor Farnell 608622 5.6nF 5% capacitor Farnell 1702663 47nF capacitor Farnell 1100392 180 ohm resistor Farnell 1700227 220 ohm resistor Farnell 1700228 470 ohm resistor Farnell 9343245 The output can drive a 32 ohm headset, but can also connect to a stereo amplifier (0.5Vrms). The frequency response is up to 19kHz, so HIFI is definitely possible (play WAV from SD card). I also experimented with a amplifier circuit, which uses more common components (no inductor, and more common resistor and capacitor values) but that takes even more board area, and uses 5V. The 5V can be dirty, so I propose to use the above circuit. Compact and simpel. Edited 2022-06-12 04:49 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
I'd used the 1.5mH inductors whem I laid it out. I've just re-done it - those 2.2mH things are pretty big! :) It's fitted on the board though. Just. :) Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5090 |
Hi Mick, With 2.2mH you get a better image rejection. I mentioned that when you have 44kHz PWM sending a 10kHz tone, that there is an image at 44-10=34kHz. You do not want 34kHz, only 10kHz. So you need to reject the 34kHz. The 1.5mH filter will also work, but this one is just a bit better in that respect. especially if you use 6.2nF capacitor in place of the 5.6nF (4.7 parallel to 1.5) or 6.0nF (12nF in series with 12nF). ![]() ![]() Normally I would not do this kind of tuning and work with the standard E3 or E6 range, but there are limitted inductor values available, and 180 ohm is the max I think the picomite could drive with it's internal resistance of 50 ohm. So this is a balancing act in combination with "available parts engineering". If you drop the 180ohm as minimum load, and would go to 150 ohm, then the filter could look like this. I will buy components and check on my picomite if 150ohm is still feasible. I am actually quite happy if 150 ohm can be done... ![]() Regards, Volhout Edited 2022-06-12 17:12 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
It's worth the board space to get rid of that 34kHz. A sacrifice I'm happy to make. :) Many thanks for your efforts in this. RS have 6.2nF MLCC, but only as 0603 or 0805. Still, if someone is already doing a bit of surface mount I might see if I can get the pads in to use one of those as an option. They can go underneath the board. RS also have the 2.2mH inductors if a second source is needed. (I like RS because their postal charges are much more reasonable than Farnell unless you want a lot of stuff.) EDIT: Got pads on for 0803 size because they are easier to solder. 0805 will fit the same pads if that's what's available. Edited 2022-06-12 16:46 by Mixtel90 Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
Volhout Guru ![]() Joined: 05/03/2018 Location: NetherlandsPosts: 5090 |
Mick, A better solution would be to layout a single 2e through hole capacitor, use 4.7nF, and solder a surface mount 1206 of 1.5nF at the bottom between the through hole solder pads. That would also allow for the (under investigation) 150 ohm driven filter that only uses a single capacitor. This is the response...(I love it) ![]() The issue with 150ohm is that the P-FET in the pico, and the N-FET in the pico have different impedances, there will be linear distortion. I have to check if that is at an acceptable number (I can calculate/simulate the number, but that doesn't say anything, I will listen to WAV played from the SD card to see if it is enjoyable). P.S. get me a link to the RS part you plan to use. I'll run it though the simulation. Volhout Edited 2022-06-12 18:02 by Volhout PicomiteVGA PETSCII ROBOTS |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
Wow... that's a lovely response! As near to perfect as anyone would need. :) I was looking at my resistors for something the other day. The leads on all my 180R value have gone bad (black and rough). That's the only value affected. No idea where they came from, but I need to get some more at some point anyway. Unfortunately RS's web site is down for scheduled maintenance until 1pm today. I'll get back to you on that. Edited 2022-06-12 18:35 by Mixtel90 Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
phil99![]() Guru ![]() Joined: 11/02/2018 Location: AustraliaPosts: 2642 |
"The leads on all my 180R value have gone bad (black and rough)" Have had that and being a tight bastard found a simple way to clean them up. Cut a slit in the end of an ink eraser (the abrasive type), push a lead in rotate it while pushing in and out. A pot scourer might work too. |
||||
Mixtel90![]() Guru ![]() Joined: 05/10/2019 Location: United KingdomPosts: 7937 |
Volhout: This is the inductor from RS. Phil: Useful tip... Thanks. :) Mick Zilog Inside! nascom.info for Nascom & Gemini Preliminary MMBasic docs & my PCB designs |
||||
thwill![]() Guru ![]() Joined: 16/09/2019 Location: United KingdomPosts: 4311 |
Hi folks, I realise this thread is now heading elsewhere, and look forward to the next PicoGAME PCB having better sound quality, but in the meantime here is a "finished" 3-channel rendition of "The Entertainer" for MMB4W, CMM2 and PicoMite; whilst not up to .wav standard the processed music data only takes up 792 bytes. ' Plays "The Entertainer" by Scott Joplin ' - also encodes it as DATA statements for playing outside of this program. ' ' Code Copyright (c) 2022 Thomas Hugo Williams ' License MIT <https://opensource.org/licenses/MIT> ' For MMBasic 5.07.03 Option Base 0 Option Default None Option Explicit On Option Break 4 On Key 3, on_break Const FILE$ = "entertainer" Const SZ% = 256 ' Const NUM_CHANNELS% = music.prompt_for_num_channels%() Const NUM_CHANNELS% = 3 Dim channel1%(SZ%), channel2%(SZ%), channel3%(SZ%), channel4%(SZ%) Dim err$ If InStr(MM.Device$, "PicoMite") Then Save FILE$ + ".bas" music.compose() music.process() music.write_data() music.play() End ' Interrupt routine to stop music and restore default Break Key. Sub on_break Play Stop Option Break 3 End End Sub ' Prompts user for number of channels to encode / play. Function music.prompt_for_num_channels%() Local s$ Do Line Input "How many channels (1-4)? ", s$ Select Case Val(s$) Case 1 To 4 : Exit Do End Select Loop music.prompt_for_num_channels% = Val(s$) End Function ' Fills channels{1-3}% with musical notes for "The Entertainer". Sub music.compose() ' ---------- Line 0 ---------- music.parse(channel1%(), "qD4,qD#4") music.parse(channel2%(), "1-") music.parse(channel3%(), "1-") ' ---------- Line 1 ---------- music.parse(channel1%(), "qE4,1C5,qE4,1C5,qE4,qC5") music.parse(channel1%(), "2C5,q-,qC5,qD5,qD#5") music.parse(channel1%(), "qE5,qC5,qD5,qE5,qE5,qB5,1D5") music.parse(channel1%(), "3C5,qD4,qD#4") music.parse(channel2%(), "1C4,1C3,1D#3,1E3") music.parse(channel2%(), "1F3,1G3,1A4,1B4") music.parse(channel2%(), "1C4,1E3,1F3,1G3") music.parse(channel2%(), "1C3,1G3,1C4,qC4,q-") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") ' ---------- Line 2 ---------- music.parse(channel1%(), "qE4,1C5,qE4,1C5,qE4,qC5") music.parse(channel1%(), "3C5,qA5,qG4") music.parse(channel1%(), "qF#4,qA5,qC5,qE5,qE5,qD5,qC5,qA5") music.parse(channel1%(), "3D5,qD4,qD#4") music.parse(channel2%(), "1C4,1C3,1D#3,1E3") music.parse(channel2%(), "1F3,1G3,1A4,1C#3") music.parse(channel2%(), "1D3,1F#3,1A4,1D3") music.parse(channel2%(), "1G3,1F3,1E3,1D3") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") ' ---------- Line 3 ---------- music.parse(channel1%(), "qE4,1C5,qE4,1C5,qE4,qC5") music.parse(channel1%(), "2C5,q-,qC5,qD5,qD#5") music.parse(channel1%(), "qE5,qC5,qD5,qE5,qE5,qB5,1D5") music.parse(channel1%(), "2C5,qC5,q-,qC5,qD5") music.parse(channel2%(), "1C3,1C4,1D#3,1E3") music.parse(channel2%(), "1F3,1G3,1A4,1B4") music.parse(channel2%(), "1C4,1E3,1F3,1G3") music.parse(channel2%(), "1C4,1G3,2C3") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") music.parse(channel3%(), "4-") ' ---------- Line 4 ---------- music.parse(channel1%(), "qE5,qC5,qD5,qE5,qE5,qC5,qD5,qC5") music.parse(channel1%(), "qE5,qC5,qD5,qE5,qE5,qC5,qD5,qC5") music.parse(channel1%(), "qE5,qC5,qD5,qE5,qE5,qB5,1D5") music.parse(channel1%(), "2C5,qC5,qE4,qF4,qF#4") music.parse(channel2%(), "qC5,q-,qC5,q-,qBb5,q-,qBb5,q-") music.parse(channel2%(), "qA5,q-,qA5,q-,qAb5,q-,qAb5,q-") music.parse(channel2%(), "qG4,q-,qG4,q-,1G4,1-") music.parse(channel2%(), "1-,1G3,qC4,q-,1-") music.parse(channel3%(), "qC4,q-,qC4,q-,qBb4,q-,qBb4,q-") music.parse(channel3%(), "qA4,q-,qA4,q-,qAb4,q-,qAb4,q-") music.parse(channel3%(), "qG3,q-,qG3,q-,1G3,1-") music.parse(channel3%(), "1-,1G2,qC3,q-,1-") ' ---------- Line 5 ---------- music.parse(channel1%(), "1G4,qA5,qG4,qG4,qE4,qF4,qF#4") music.parse(channel1%(), "1G4,qA5,qG4,qG4,qE5,qC5,qG4") music.parse(channel1%(), "qA5,qB5,qC5,qD5,qE5,qD5,qC5,qD5") music.parse(channel1%(), "2G4,qG4,qE4,qF4,qF#4") music.parse(channel2%(), "1E4,qF4,qE4,qE4,q-,1-") music.parse(channel2%(), "1E4,qF4,qE4,qE4,q-,1-") music.parse(channel2%(), "4-") music.parse(channel2%(), "4-") music.parse(channel3%(), "1C4,1-,1G3,1-") music.parse(channel3%(), "1C4,1-,1G3,1-") music.parse(channel3%(), "2F3,2G3") music.parse(channel3%(), "1C3,1G3,1C4,1-") ' ---------- Line 6 ---------- music.parse(channel1%(), "1G4,qA5,qG4,qG4,qE4,qF4,qF#4") music.parse(channel1%(), "1G4,qA5,qG4,qG4,qG4,qA5,qA#5") music.parse(channel1%(), "1B5,q-,1B5,qA5,qF#4,qD4") music.parse(channel1%(), "2G4,qG4,qE4,qF4,qF#4") music.parse(channel2%(), "1E4,qF4,qE4,qE4,q-,1-") music.parse(channel2%(), "1E4,qF4,qE4,qE4,q-,1-") music.parse(channel2%(), "4-") music.parse(channel2%(), "4-") music.parse(channel3%(), "1C4,1-,1G3,1-") music.parse(channel3%(), "1C4,1-,1G3,1C#4") music.parse(channel3%(), "2D4,2D3") music.parse(channel3%(), "qG3,q-,qG3,q-,1A4,1B4") ' ---------- Line 7 ---------- music.parse(channel1%(), "1G4,qA5,qG4,qG4,qE4,qF4,qF#4") music.parse(channel1%(), "1G4,qA5,qG4,qG4,qE5,qC5,qG4") music.parse(channel1%(), "qA5,qB5,qC5,qD5,qE5,qD5,qC5,qD5") music.parse(channel1%(), "2C5,qC5,qG4,qF#4,qG4") music.parse(channel2%(), "1E4,qF4,qE4,qE4,q-,1-") music.parse(channel2%(), "1E4,qF4,qE4,qE4,q-,1-") music.parse(channel2%(), "4-") music.parse(channel2%(), "4-") music.parse(channel3%(), "1C4,1-,1G3,1-") music.parse(channel3%(), "1C4,1-,1G3,1-") music.parse(channel3%(), "2F3,2G3") music.parse(channel3%(), "1C3,1G3,1C4,1-") ' ---------- Line 8 ---------- music.parse(channel1%(), "1C5,qA5,qC5,qC5,qA5,qC5,qA5") music.parse(channel1%(), "qG4,qC5,qE5,qG5,qG5,qE5,qC5,qG4") music.parse(channel1%(), "1A5,1C5,qE5,1D5,qD5") music.parse(channel1%(), "3C5,1-") music.parse(channel2%(), "qF4,q-,qF4,q-,qF#4,q-,qF#4,q-") music.parse(channel2%(), "qG4,q-,qG4,q-,qE4,q-,qE4,q-") music.parse(channel2%(), "qF4,q-,qF4,q-,qG4,q-,qG4,q-") music.parse(channel2%(), "1C5,1G4,1C4,1-") music.parse(channel3%(), "qF3,q-,qF3,q-,qF#3,q-,qF#3,q-") music.parse(channel3%(), "qG3,q-,qG3,q-,qE3,q-,qE3,q-") music.parse(channel3%(), "qF3,q-,qF3,q-,qG3,q-,qG3,q-") music.parse(channel3%(), "1C4,1G3,1C3,1-") End Sub ' Parses comma separated list of notes. ' ' @param channel%() parsed notes are appended to this array. ' @param s$ comma separated list. Sub music.parse(channel%(), s$) Local s_idx% = 1 Local ch$ = "," Do While ch$ = "," If music.parse_note%(channel%(), s$, s_idx%) <> 0 Then Error err$ + " : s_idx = " + Str$(s_idx%) EndIf Inc s_idx% ch$ = Mid$(s$, s_idx%, 1) Inc s_idx% Loop End Sub ' Parses single note. ' ' @param channel%() parsed note is appended to this array. ' @param s$ note is parsed from this string ... ' @param s_idx% ... starting at this index. On exit this will ' contain the index of the last character parsed. ' @return 0 on success, -1 on error. Error message will ' be in the global err$ variable. Function music.parse_note%(channel%(), s$, s_idx%) music.parse_note% = -1 Local i% Local ch$ = Mid$(s$, s_idx%, 1) ' Parse duration. Local duration% Select Case ch$ Case "q": duration% = 1 Case "1", "2", "3", "4": duration% = 2 * Val(ch$) Case Else err$ = "Syntax error: expected duration" Exit Function End Select Inc s_idx% ch$ = Mid$(s$, s_idx%, 1) ' Parse note. Local n% = 0 ' 0 = Rest, 1 = A0 Select Case ch$ Case "A" : n% = 1 Case "B" : n% = 3 Case "C" : n% = 4 Case "D" : n% = 6 Case "E" : n% = 8 Case "F" : n% = 9 Case "G" : n% = 11 Case "-" : ' Do nothing Case Else err$ = "Syntax error: expected note" Exit Function End Select If n% = 0 Then For i% = 1 To duration% LongString Append channel%(), Chr$(0) Next music.parse_note% = 0 Exit Function EndIf Inc s_idx% ch$ = Mid$(s$, s_idx%, 1) ' Parse b or #. Local off% = 0 Select Case ch$ Case "b" : off% = -1 Case "#" : off% = 1 End Select If off% <> 0 Then Inc n%, off% Inc s_idx% ch$ = Mid$(s$, s_idx%, 1) EndIf ' Parse octave. If Not Instr("012345678", ch$) Then err$ = "Syntax error: expected octave" Exit Function EndIf Inc n%, 12 * Val(ch$) ' Write note into buffer. For i% = 1 To duration% LongString Append channel%(), Chr$(n%) Next music.parse_note% = 0 End Function ' Combines the individual channels into a single global music%() array. Sub music.process() ' Terminate each channel with 255 and determine the maximum length. Local max_len% = 0, i%, j% For i% = 1 To NUM_CHANNELS% Execute "LongString Append channel" + Str$(i%) + "%(), Chr$(&hFF)" max_len% = Max(max_len%, Eval("LLen(channel" + Str$(i%) + "%())")) Next ' Pad max_len% to be a multiple of 8. Do While max_len% Mod 8 > 0 : Inc max_len% : Loop ' Pad each channel with 255 until all the same length. For i% = 1 To NUM_CHANNELS% Do While Eval("LLen(channel" + Str$(i%) + "%())") < max_len% Execute "LongString Append channel" + Str$(i%) + "%(), Chr$(&hFF)" Loop Next ' Combine the channels into a single music buffer. Dim music%(1 + (NUM_CHANNELS% * max_len% / 8)) For i% = 0 To max_len% - 1 For j% = 1 To NUM_CHANNELS% Execute "LongString Append music%(), Chr$(LGetByte(channel" + Str$(j%) + "%(), i%))" Next Next End Sub ' Writes music%() array into a file as DATA statements. Sub music.write_data() Local count% = 0, i%, p% = Peek(VarAddr music%()) + 8 Open "entertainer.inc" For Output As #1 Print #1, "Data " Format$(LLen(music%()), "%-6g") "' Number of bytes of music data." Print #1, "Data " Format$(NUM_CHANNELS%,"%-6g") "' Number of channels." For i% = 0 To LLen(music%()) - 1 Step 8 Print #1, Choice(count% = 0, "Data ", ", "); Print #1, "&h" Hex$(Peek(Integer p%), 16); Inc p%, 8 Inc count% If count% = 4 Then Print #1 : count% = 0 Next Close #1 End Sub ' Plays the contents of the music%() array using interrupts. Sub music.play() Dim music_ptr% = Peek(VarAddr music%()) + 8 SetTick 200, music.play_interrupt, 1 Do While music_ptr% <> 0 : Loop End Sub ' Interrupt routine playing a single half-beat (per channel) from the music%() array. Sub music.play_interrupt() Local i%, n%, halted% = 0 For i% = 1 To NUM_CHANNELS% n% = Peek(Byte music_ptr%) Select Case n% Case 0 Play Sound i%, B, O Print Str$(i%) ": Rest" Case 1 To 254 Play Sound i%, B, S, 440 * 2^((n% - 49) / 12.0), 15 Print Str$(i%) ":" 440 * 2^((n% - 49) / 12.0) " hz" Case 255 Play Sound i%, B, O Print Str$(i%) ": Halted" Inc halted% End Select Inc music_ptr% Next If halted% = NUM_CHANNELS% Then music_ptr% = 0 ' Halt End Sub Best wishes, Tom Edited 2022-06-13 01:15 by thwill MMBasic for Linux, Game*Mite, CMM2 Welcome Tape, Creaky old text adventures |
||||
![]() ![]() ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |