Question about 2-channel beeper music
I confess I haven't tried all the available beeper utilities and software. I always found music software confusing and trackers are not for me. I know about Beepola, but this is a little bit different.
Let's suppose I want to use the good old beeper from BASIC and want to play two-channel music without having to leave BASIC. Let's say I created DATA statements (I know, I know...) for each channel. From all the currently available software and routines, is there anything I could use to play my two-channel tune and at the same allow me to do things between each note? I'm referring to anything I may want to do from BASIC like for example key detection, print something, etc.
Pause between notes or silence duration could be entered the same way as notes, but with a high number. 1,255, for example, could be interpreted as "pause for one second". Other codes could be used to determine if it stops at the end or loops instead.
I could also store both channels in memory instead of using DATA statements and figure out how to store negative notes and note duration. It would be more efficient, but I prefer the DATA statements.
I know what I'm asking for may be complicated because of the timing. How to return to BASIC after one note in one channel if a note in another channel is still playing? Is this something where interrupts could help? I really don't know.
What I'm really asking is to be able to compose music in BASIC as I always did, but this time with two channels.
Let's suppose I want to use the good old beeper from BASIC and want to play two-channel music without having to leave BASIC. Let's say I created DATA statements (I know, I know...) for each channel. From all the currently available software and routines, is there anything I could use to play my two-channel tune and at the same allow me to do things between each note? I'm referring to anything I may want to do from BASIC like for example key detection, print something, etc.
Pause between notes or silence duration could be entered the same way as notes, but with a high number. 1,255, for example, could be interpreted as "pause for one second". Other codes could be used to determine if it stops at the end or loops instead.
I could also store both channels in memory instead of using DATA statements and figure out how to store negative notes and note duration. It would be more efficient, but I prefer the DATA statements.
I know what I'm asking for may be complicated because of the timing. How to return to BASIC after one note in one channel if a note in another channel is still playing? Is this something where interrupts could help? I really don't know.
What I'm really asking is to be able to compose music in BASIC as I always did, but this time with two channels.
Post edited by zxbruno on
Comments
My brain finds it easy to work with BEEP in a linear form. No patterns, ornaments and other things I know nothing about. All I know is how to choose the duration, note and find a way to pause between notes when necessary. To do this with one channel is easy for me. What I would like to know is how to do it in with two virtual channels and make it sound like just like two Spectrums playing BASIC BEEP music at the same time. Ideally the machine code routine would allow me to select which line to read DATA from. If the data for the first channel started, for example, at line 8000 in BASIC and data for the second one started at 9000, the routine would allow me to POKE those values and call it with RANDOMIZE USR to start playing the two-channel tune.
Unsure if any of this makes any sense. :)
I've never done this so this is just theory. 1 bit modulation uses time between switches from 1 to 0 and back to modulate sounds. If you switch it on and off 440 times per second its an "A" note.
Imagine you have a vector of zeroes and ones each element being apart from another by fixed amount of time telling you how to do your switching. You can have a vector for each note. If you want to play a chord this paper suggests you can joint frequencies together (form a chord) by simple boolean OR operation between two vectors (Xenakis sieves).
I don't think BASIC is fast enough for optimal results. You'd need two OUT command, for example: And then by changing the pause according to your vector you could do modulation. You'd need to know precise BASIC interpretation timing to do this accurately. And it would have to be fast enough.
For a more complex player with better sound machine code is a must, and in this case DATA is not acceptable due to low storage efficiency and thus slow access. However, text strings are acceptable, it is possible to create PLAY-lile syntax even.
Still, normally beeper music is added into BASIC or code programs by saving a code block from a music editor and calling it through RANDOMIZE USR.
Other than that, I suspect someone would have to write something.
Well, you can do it that way, but if you're going to the effort of writing a machine code program to be able to read data from somewhere and do two channels (or more than two channels), you can exploit the analogue-to-digital converter that every Spectrum has. The beeper circuit has enormous reactance (deliberately) - there's an RC low pass filter in there. You can exploit this to make analogue wave forms using a technique called PDM (pulse density modulation), or PWM (pulse width modulation). Basically the low pass filter will effectively give an average voltage if you rapidly switch between 1 and 0 on the beeper output. If you rapidly switch the beeper channel between 1 and 0 with equal times in both 1 and 0, you'll get a DC voltage of about 2.5 volts on this circuit. Lengthen the time spent with 1 being output, and shorten the time with 0 being output, and the voltage will rise. You can actually make a reasonable (but slightly noisy) sine wave (or indeed pretty much any wave form) by this method. And like this you can make proper two or more channel music with just the beeper circuit. (super audio CD works with a slightly refined version of this method - the discs just contain a train of pulse density modulated 1s and 0s to make the wave form when you play an SA-CD, as opposed to regular CDs which hold discrete 16 bit values for each sample).
Just to show how the low pass filter rolls off and changes the wave form, using different frequencies. All these are on the same vertical scale:
BEEP 1,1:
BEEP 1,20:
BEEP 1,40:
BEEP 1,60:
Pure BASIC just isn't fast enough to really exploit this, but machine code is, and there's probably many beeper tunes that take advantage of the beeper circuit's low pass filter to make analogue wave forms.
Whilst I haven't tackled beeper music, I did spend a bit of time looking at playing multi-bit sound samples on the beeper and after many refinements ended up with a 2-bit player which drove the beeper at a rate of 60 T-states per cycle (20 for the low-bit, 40 for the high-bit of each sample) so the beeper was cycled at about 58.3kHz, with the requirement that each sample was sent at least three times (so it could playback 2-bit samples at an effective sample rate of 19.4kHz, 14.6kHz, 11.7kHz, 9.7kHz etc). It worked as intended, but noise reduction of the source audio before processing was a big must for music.
I also did a 3-bit player which in its final version cycled the beeper every 84 T-states (12 low, 24 mid, 48 high-bit), the fastest I was able to get it as I could see no way to get it down to the theoretical fastest of 77 T-states (11+22+44) -- 11 T-states being the fastest OUT instruction available. This was considerably better than the 2-bit player as it was still driving the beeper at around 41.7kHz, and although it required each sample to be sent at least four times, that still allowed for a sample rate of 10.4kHz which worked pretty well even without any noise reduction due to the higher quality of the samples being played. 3-bit samples are a bit of a hassle to work with as they cross over byte-boundaries (eight samples per three bytes) but the end result was worth it.
I toyed with a 4-bit player unsuccessfully. I did get it to the maximum speed of 165T (11+22+44+88 ) but because it was only driving the beeper at 21.2kHz, was inferior in overall sound quality to the 3-bit player.
For music, a 2-channel, interrupt-driven time-limited routine should be quite straightforward to write, provided you're dealing with fairly high pitched notes (though if you're happy with the routine taking over 50% CPU time and being called every 1/25th of a second, it could handle a lot more).
3-channel beeper music is also probably possible when you get the loop running fast enough, though getting the speeds I mentioned above took some serious tweaking.
...and existing. :) As well as 4ch and 5ch are. :)
http://mister_beep.republika.pl/
Uses beeps, 2 Channel sound. Easy to use. Saves to memory blocks.
Job done!
Bish-Bash-Bosh!