Question about 2-channel beeper music

edited May 2012 in Development
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.
Post edited by zxbruno on

Comments

  • edited May 2012
    What about the 128 PLAY command? That's in BASIC and supports three channels.
  • edited May 2012
    I tried to use PLAY in the past and couldn't get my head around it. I do prefer the 48K editor and the logic behind the BEEP command (duration,note). If there was a way to use the AY in USR 0 mode without complicated OUT commands I would use that.

    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. :)
  • edited May 2012
    zxbruno wrote: »
    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.

    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:
    OUT (C),D ; 12 t-states, switch on the 4th bit of port
    ; ...pause...
    OUT (C), E ; and off
    
    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.
  • edited May 2012
    I recall a game that played pseudo 2 channel beeper music from DATA statements, it used BEEP and 'arpeggio' effect to create multichannel illusion.

    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.
  • edited May 2012
    You could try Jim Newall's 48k Sound System from Your Sinclair. It provides 2-channel sound with features similar to PLAY but works on the 48k Spectrum and uses a simpler syntax. Hmmm, well, actually, comparing the two, it uses a command set which, apart from "!", matches the equivalent PLAY commands, but with reduced ranges. The m/code uses 904 bytes.
    a-g or A-G - pitch of note within current octave
    $ - use after a note to flatten it
    # - use after a note to sharpen it
    O - followed by channel (A or B) and then a number (1-3) sets octave
    1-9 - sets length of notes
    & - denotes a rest
    T - followed by a number from 1-12 sets the tempo
    () - enclose a phrase to be repeated
    ! - sound FX - follow by three characters for a variety of sound effects
  • edited May 2012
    The problem with PLAY is that you can't do anything else while it's going on, and you can't tell how long BASIC is going to spend doing anything with any accuracy, so it's impossible to play anything in time. The best way to play music during BASIC execution is via interrupts. It's fairly trivial to write an interrupt routine to drive something like Music Box, or any of the other music routines that enable you to call a single time and return. The main downside of Music Box is that you're limited to fairly short tunes, unless you implement some kind of tracker code.
  • edited May 2012
    Gasman wrote a while back a script to convert MIDI files to BASIC statements to make BEEP music, perhaps you might want to try that. You'll have to search the forums. It made a very nice rendition of the Minute Waltz, IIRC.

    Other than that, I suspect someone would have to write something.
    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.

    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:

    beep1,1.png

    BEEP 1,20:

    beep1,20.png

    BEEP 1,40:

    beep1,40.png

    BEEP 1,60:

    beep1,60.png

    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.
  • edited May 2012
    Once you write in pure machine-code, multi-channel sound on the 48K spectrum beeper is quite straightforwards to produce, though you'll need a chart of Z80 instruction T-states to hand as every T-state is critical in ensuring it plays correctly.

    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.
  • edited May 2012
    There was a 8-channel beeper music player for 22 years now. So 3-channel players are absolutely possible.
  • edited May 2012
    Shiru wrote: »
    There was a 8-channel beeper music player for 22 years now. So 3-channel players are absolutely possible.

    ...and existing. :) As well as 4ch and 5ch are. :)
    ZX Spectrum 48K BEEPER Music:
    http://mister_beep.republika.pl/
  • edited May 2012
    Use 'WHAM'the Music Box

    Uses beeps, 2 Channel sound. Easy to use. Saves to memory blocks.
    Job done!

    Bish-Bash-Bosh!
  • edited May 2012
    I can't think of music as "CDEF", much less sheet music. When I think about music I see all notes as numbers. But thanks anyway. :)
Sign In or Register to comment.