Ok folks, I just updated the rules - submissions to the Code category don't need to be anonymous if you're worried about people stealing your code.
977 2015-07-16 19:36:22
Re: Tutorial: How to Write a 1-Bit Music Routine (56 replies, posted in General Discussion)
Part 7: Variable Pulse Width
Alright, if you've come this far, you should be able to write a pretty decent basic 1-bit sound routine. But the real fun of 1-bit coding has only started. From this point on, coding for 1-bit sounds becomes somewhat of an art form - you've got to use your creativity and imagination in order to build a routine that does something out of the ordinary.
I'm by no means an assembly expert, and don't understand half of what all these crazy beeper engines out there are doing. So I can only share those few tricks and techniques that I have so far discovered/reverse-engineered/been told about.
Ok, let's talk about variable pulse width. Varying the pulse width has a number of useful effects, most importantly the ability to produce more interesting timbres when used in conjunction with the pulse interleaving method. (In conjunction with PFM, it can be used to create volume envelopes, but this is not what this part of the tutorial is about.)
Imagine a classic pulse interleaving routine with 16-bit counters, as explained in part 4. The basic procedure for updating a channel's state and counters is:
counter := base + counter
IF carry THEN
state := state XOR ch_toggle
ENDIF
OUTPUT state
This will output a square wave with a 50:50 duty cycle, because half of the time the output is 0, and the other half it's 1.
Well, there is another of way of doing this.
counter := base + counter ld hl,nnnn \ add hl,bc \ ld b,h \ ld c,l
IF counter < 8000h THEN ld a,h \ cp #80
state := off ld a,0 \ jr nc,skip
ELSE
state := on ld a,#10
ENDIF skip:
OUTPUT state out (#fe),a
So, instead of waiting until the counter wraps from FFFFh to 0h, we now check if it has wrapped from FFFFh to 0h or from 7FFFh to 8000h. So in effect we change the state twice as often, but we will still get a 50:50 square wave. Now what happens if we compare against a value other than 8000h? You probably can guess: Yes, that will change our duty cycle. So, to get a 25:75 square wave for example, we'd compare against 4000h, for 12.5:87:5 we compare against 2000h, and so forth. Simple, right?
If only we wouldn't have to deal with that ugly conditional jump that ruins our timing. Well, in Z80 asm there's a handy trick. It is used in Shiru's Tritone, for example.
ld hl,nnnn \ add hl,bc \ ld b,h \ ld c,l ;do the counter math as usual
ld a,h \ cp nn ;compare against our chosen value
sbc a,a ;A will become 0 if there was no carry, else it becomes FFh
and #10 ;ANDing 10h will leave A set to either 0 or 10h, depending the on previous result
out (#fe),a
978 2015-07-15 23:27:16
Re: Tutorial: How to Write a 1-Bit Music Routine (56 replies, posted in General Discussion)
Part 6: Drums
We got ourselves a nicely working 1-bit routine now, but something is missing. Now what could that be? Oh right, we need some drums!
As usual, there are several approaches to realize drum sounds. The by far most common one is the "interrupting click drum" method. The idea is that in order to play drum sounds, you briefly pause playback of the tone channels and squeeze the drums in between the notes. In order for listeners to not realize that tone playback has been interrupted, the drum sounds need to be quite short, typically in the range of a few hundred up to a couple of thousand t-states.
There are countless ways of actually producing the drum sounds - pretty much anything that makes noise goes. I'll only post a very primitive example here to get you started, the rest is entirely up to your creativity
We'll need 3 variables:
data_pointer - a pointer into ROM or another array of arbitrary values. On ZX Spectrum, we'll use HL.
timer - a counter to keep track of the drum length. We'll use B on the Speccy.
state - our good friend, the output state. Let's use the accumulator A.
and a constant which equals the state being on/1, let's call it ch_on.
Now we do the following:
PSEUDOCODE ZX ASM
drumloop:
state := (data_pointer) AND ch_on ld a,(hl) \ and #10
OUTPUT state out (#fe),a
INCREMENT data_pointer inc hl
DECREMENT timer
IF timer != 0 THEN djnz drumloop
GOTO drumloop
ELSE
EXIT ret
ENDIF
This will create a very short noise burst - for better sound, you may want to add some bogus commands for wasting a few cycles in the loop. You would typically trigger this code at some point during reading in data for the next sound loop.
One last thing, you will need to adjust the main soundloop timer. Otherwise you will get an unwanted groove effect every time a drum is played. So you need to count the number of t-states your drum code takes to execute. Divide this number by the amount of t-states your sound loop takes, and subtract the result from the main timer every time you trigger a drum.
Another approach to creating drums is the "PWM sample" method. PWM (pulse-width modulation) samples are a distant relative of the more widely known PCM (WAV) samples. In PCM data, each data value (also known as sample) represents the relative volume at a given time. However, for 1-bit devices, volume is rather meaningless as you have only two volume states - nothing (off, 0) or full blast (on, 1). So instead, in PWM data each sample represents the time taken until the 1-bit output state will be toggled again. Sounds a bit confusing? Well, you can also think of PWM data as a sequence of frequencies. So, think about how a kickdrum sounds: It starts at a very high frequency, then quickly drops and ends with a somewhat longer low tone. So, as a PWM sample, we could create something like this:
db #80, #80, #70, #70, #60, #60, #60, #50 ;high start and quick drop
db #50, #50, #50, #40, #40, #40, #40, #40
db #30, #30, #30, #30, #30, #30, #20, #20
db #20, #20, #20, #20, #20, #20, #20, #10
db #10, #10, #10, #10, #10, #10, #10, #08
db #08, #08, #08, #08, #08, #08, #08, #08
db #04, #04, #04, #04, #04, #04, #04, #04 ;slow low end
db #04, #04, #04, #04, #04, #04, #04, #04
db #02, #02, #02, #02, #02, #02, #02, #02
db #02, #02, #02, #02, #02, #02, #02, #02
db #02, #02, #02, #02, #02, #02, #02, #02
db #00 ;end marker
Still confused? Well, luckily there's a utility that you can use to convert PCM to PWM. It's called pcm2pwm and can be downloaded here.
Now, how to play back this data? It couldn't be simpler. We need 3 variables:
data_pointer - a pointer that points to the memory location of the PWM data. We'll use HL in our ZX Spectrum Z80 asm example.
counter - a counter that is fed with the sample values. We'll use B.
state - the output state. We'll use A' (the "shadow" accumulator).
Also, we need the ch_toggle constant as usual.
PSEUDOCODE ZX ASM
state := on ld a,#10
drumloop:
counter := (data_pointer) ex af,af' \ ld b,(hl)
IF counter == 0 THEN xor a \ or b
EXIT ret z
ENDIF
ex af,af'
innerloop:
OUTPUT state out (#fe),a
DECREMENT counter
IF counter != 0 THEN djnz innerloop
GOTO innerloop
ELSE
INCREMENT data_pointer inc hl
state := state XOR ch_toggle xor #10
GOTO drumloop jr drumloop
ENDIF
You can call this code inbetween notes, just like with the interrupting click drum method. However, this will lead to the usual problems - the drum sound needs to be very short, and you need to correct the main soundloop timer. A much better way to use PWM samples is to treat them like an extra channel, and trigger them within the soundloop alongside with the regular tone channels. The above code should be easy to adjust, so I'll leave that to you
Edit 15-12-01: Link to new version of pcm2pwm added.
979 2015-07-15 23:22:54
Re: Tutorial: How to Write a 1-Bit Music Routine (56 replies, posted in General Discussion)
Part 5: Improving the Sound
You've followed this tutorial series and have come up with a little 1-bit sound routine of your own design. Only problem - it still sounds crap - notes are detuned, there are clicks and crackles all over the place, and worse of all, you hear a constant high-pitched whistle over the music. So, it's time to address some of the most common sources of unwanted noise in 1-bit sound routines, and how to deal with them.
Timing Issues
In order to keep the pitch stable, you need to make sure that the timing of your sound routine is as accurate as possible, ie. that each iteration of the sound loop takes exactly the same time to execute.
Let's take a look again at the first example from part 1. We can see that that code is not well timed at all:
soundLoop:
xor a ;4
dec b ;4
jr nz,skip1 ;12/7
ld a,#10 ;7
ld b,c ;4
skip1:
out (#fe),a ;11
xor a ;4
dec d ;4
jr nz,skip2 ;12/7
ld a,#10 ;7
ld d,e ;4
skip2:
out (#fe),a ;11
dec hl ;6
ld a,h \ or l ;8
jr nz,soundLoop ;12
;78/92t
Due to the two jumps, there are four different paths through the core (no jump taken, jump 1 taken, jump 2 taken, both jumps taking), and the sound loop length thus varies up to 12 t-states - that's more than 15% of the sound loop length, and therefore clearly unacceptable. We need to make sure that the sound loop will always take the same amount of time regardless of the code path taken. One possible solution would be to introduce an additional time-wasting jump:
soundLoop:
xor a ;4
dec b ;4
jr nz,wait1 ;12/7----
ld a,#10 ;7
ld b,c ;4
nop ;4-------7+7+4+4=22
skip1:
out (#fe),a ;11
xor a ;4
dec d ;4
jr nz,wait2 ;12/7
ld a,#10 ;7
ld d,e ;4
nop ;4
skip2:
out (#fe),a ;11
dec hl ;6
ld a,h \ or l ;8
jr nz,soundLoop ;12
;100/100t
wait1:
jp skip1 ;12+10=22
wait2:
jp skip2
There are other possibilities, but I'll leave that for another part of this tutorial.
Row Transition Noise
A common moment for unwanted noise to occur is ironically not during the sound loop, but between notes - the moment when you're reading in new data and updating your counters etc. This is called row transition noise.
Row transition noise is very difficult to avoid. Your focus should therefore be on reducing transition noise rather than trying eliminating it. The key to this is to read in data as fast and efficiently as possible. Not much else can be said about this, except: Make sure you optimize your code. For starters, WikiTI has an excellent article on optimizing Z80 code.
Theoretically, there is a way for eliminating transition noise, though in practise very few existing beeper engines use it (Jan Deak's ZX-16 being a notable example). That way is to do parallel computation, ie. read in data while the sound loop is running. Obviously this is not only rather difficult, but also it is usually only feasible on faster machines - on ZX Spectrum, it will most likely slow down your sound loop too much.
Which brings us to another problem...
Discretion Noise
Discretion noise, also known as parasite tone, commonly takes the form of a high-pitched whistling, whining, or hissing. It inevitably occurs when mixing software channels into a 1-bit output and cannot be avoided. It is usually not a big deal when doing PFM, but can be a major hassle with Pulse Interleaving. The solution is to push the parasite tone's frequency above the audible range. In other words, if you hear discretion noise, your sound loop is too slow. As a rule of thumb, on ZX Spectrum (3,5 MHz) your sound loop should not exceed 250 t-states.
Let's take a look at the asm example from part 4 again. At the end of the sound loop, there is a relative jump back to the start (jr nz,soundLoop). A better solution would be to use an absolute jump (jp nz,soundLoop) instead, because an absolute jump always takes 10 t-states, but a relative jump takes 12 if the jump is actually taken, which we assume to be the case here.
Also, leading up to the jump we have
dec ix
ld a,ixh \ or ixl
jr nz,soundLoop
which takes a whopping 38 t-states. It may be a good idea to replace it with
dec ixl
jr nz,soundLoop
dec ixh
jp nz,soundLoop
This will take only 20 t-states except when the first jump is not taken. It will introduce a timing shift every 256 sound loop iterations, but this is usually not a major problem, as it happens at a frequency below audible range.
I'll cover some more tricks for speeding up synthesis in one of the following parts.
IO Contention
This section addresses a problem that is specific to the ZX Spectrum. You can most likely skip this section if you're targetting another platform.
IO Contention is an issue that occurs on all older Spectrum models up to and including the +2. The implication is that in certain circumstances, writing values to the ULA will introduce an additional delay in the program execution. You don't need to understand the full details of this, but if you are curious you can read all about IO contention here.
What's important to know is that delay caused by IO contention affects our sound loop timing. Which is bad, as I've explained above. For sound cores with only one OUT command the solution is rather trivial: You just need to make sure that the number of t-states your sound loop takes is a multiple of 8. For ideal sound in cores with multiple OUTs however, the timing distance between each OUT command must be a multiple of 8. Naturally this is pretty tricky to achieve (and chances are your core will sound ok without observing this), but keep it in mind as a general guideline.
Edit 15-12-01: Added/changed info as suggested by introspec.
980 2015-07-14 21:39:32
Re: Tutorial: How to Write a 1-Bit Music Routine (56 replies, posted in General Discussion)
Part 4: 16-Bit Counting
If you have tried the methods in Part 1, you might have noticed that it produces a lot of detuned notes at higher frequencies. This is because 8-bit values are too small to properly represent the common range of musical notes.
So, in order to increase the usable tonal range of your engine, you should use 16-bit values for your frequency counters. However, this poses another problem: As 1-bit DACs are usually hooked up to slow 8-bit CPUs, 16-bit maths are generally rather slow in execution. So simply decrementing our frequency counters like in Part 1 will most likely be too slow. We therefore need to use a trick to speed up counting.
The trick, in this case, is to add up counters repeatedly and check for carry (ie, see if the result was >FFFFh.)
I'll explain how this works for the Pulse Interleaving method. We need the following variables:
base1 - the base frequency of channel 1. We'll put this in memory on ZX Spectrum.
base2 - the base frequency of channel 2. We'll put this in memory on ZX Spectrum.
counter1 - the actual frequency counter of channel 1. We'll use BC on the Spectrum.
counter2 - the actual frequency counter of channel 2. We'll use DE on the Spectrum.
state1 - output state of channel 1. Let's use IYh.
state2 - output state of channel 2. Let's use IYl.
timer - note length counter. We'll use IX.
and our usual ch_toggle constant.
disable interrupts di
state1 := 0 ld iy,0
state2 := 0
counter1 := 0 ld bc,0
counter2 := 0 ld de,0
soundLoop: soundLoop:
counter1 := base1 + counter1 ld hl,nnnn \ add hl,bc \ ld b,h \ ld c,l ;nnnn = base1
IF previous operation resulted in carry jr nc,skip1
state1 := state1 XOR ch_toggle ld a,iyh \ xor #10 \ ld iyh,a
ENDIF skip1:
OUTPUT state1 ld a,iyh \ out (#fe),a
counter2 := base2 + counter2 ld hl,nnnn \ add hl,de \ ex de,hl ;nnnn = base2
IF previous operation resulted in carry jr nc,skip2
state2 := state2 XOR ch_toggle ld a,iyl \ xor #10 \ ld iyl,a
ENDIF skip2:
OUTPUT state2 ld a,iyl \ out (#fe),a
DECREMENT timer dec ix
IF timer == 0 then ld a,ixh \ or ixl
GOTO soundLoop jr nz,soundLoop
ELSE
ENABLE INTERRUPTS ei
EXIT ret
ENDIF
Of course the above asm code can be optimized further, but that I will leave to you, the programmer
Beware that in order to calculate the counter values, you will need to adapt the formula from Part 3. Simply change it to
fn = f0 * (a)^n.
981 2015-07-14 21:39:05
Re: Tutorial: How to Write a 1-Bit Music Routine (56 replies, posted in General Discussion)
Part 3: Calculating Note Counters
So you've got your sound loop and your data loader all set up, but now you need to actually fill in some music data. For that, you will need to know how
to calculate the note/frequency counter values.
Basically, all you need to know is the magic formula
fn = int(f0 / (a)^n)
where...
... f0 is the base note counter value you want to use
... n is the distance to the base counter value in halftones
... fn is the frequency of the note n halftones away from the base note
... a is the twelth root of 2, approx. 1.059463094
Unless you want concert pitch, it doesn't really matter so much which base value (f0) you use, so you might as well use something high, e.g. 254.
Now, to calculate the value for the base note plus one halftone, you do:
f1 = int(254 / 1.059463094^1) = 239
For the base value plus two halftones, it's
f2 = int(254 / 1.059463094^2) = 226
As you can see, the lower the note, the higher the counter value. This makes sense because we decrement these values in the sound loop. A higher value means it takes longer for the counter to reach zero and reset, therefore the output is activated/toggled less frequently - which of course results in a lower frequency.
982 2015-07-14 21:38:19
Re: Tutorial: How to Write a 1-Bit Music Routine (56 replies, posted in General Discussion)
Part 2: Adding a Loader/Wrapper
In Part 1, I talked about the two different synthesis methods commonly found in 1-bit/beeper engines. Now, in order to transform these synthesis cores into an actualy 1-bit player, you'll need to add some code to load in the desired frequency values.
First, you should think about the layout of your music data. It's common to use a two-part structure. The first part is the song sequence, which is actually a list of references to the pattern data which follows in part 2. So, an example music data file could look like this:
PSEUDOCODE ZX ASM
sequence { sequence:
pattern00 dw pattern00
pattern01 dw pattern01
pattern02 dw pattern02
pattern03 dw pattern03
sequence_end dw #0000
}
pattern00 { pattern00:
1st note ch1, 1st note ch2 db nn,db nn
2nd note ch1, 2nd note ch2 db nn,db nn
3rd note ch1, 3rd note ch2 db nn,db nn
... ...
pattern_end db #ff
}
pattern01 { pattern01:
... ...
}
... ...
Reading in data like this is theoretically quite trivial, but may get a bit confusing if you have to write the loader in assembly language.
For the following example, we'll use the usual counter1, counter2, backup1, backup2, and timer variables from the example in part 1. In addition, we'll need
two pointers:
seq - will be our pointer to the song sequence
pat - will be our pointer to the current pattern.
Now, you'll need to
init: init:
seq := sequence+0 ld hl,sequence \ push hl
read_sequence:
pat := (seq) pop hl \ ld e,(hl) \ inc hl \ ld d,(hl)
IF pat == sequence_end THEN xor a \ or d
exit ret z
ENDIF
INCREMENT seq inc hl \ push hl \ push de
read_pattern:
counter1 := (pat) pop de \ ld a,(de) \ ld b,a
IF counter1 == pattern_end THEN cp #ff
GOTO read_sequence jr z,read_sequence
ENDIF
backup1 := counter1 ld c,b
INCREMENT pat inc de
counter2 := (pat) ld a,(de)
INCREMENT pat inc de \ push de
backup2 := counter2 ld h,a \ ld l,h
CALL soundLoop call soundLoop
GOTO read_pattern jr read_pattern
Note that this doesn't set the timer - I think you can figure out yourself how to do that.
983 2015-07-14 21:37:23
Topic: Tutorial: How to Write a 1-Bit Music Routine (56 replies, posted in General Discussion)
Hiya folks, in this tutorial I'm going explain how you can write your own multi-channel music routines for 1-bit devices. If you have any questions or suggestions, feel free to post in this thead anytime
There are various 1-bit synthesis methods. I'm going to demonstrate only the two most common ones here. For explanation I'll mostly use my own flavour of pseudo code, and parallel to that I'll give real-life Z80 asm examples, as it would be done on a ZX Spectrum computer.
Index
Part 1: The Basics
Part 2: Adding a Loader/Wrapper
Part 3: Calculating Note Counters
Part 4: 16-Bit Counting
Part 5: Improving the Sound
Part 6: Drums
Part 7: Variable Pulse Width
Part 8: Why PFM Engines Have No Bass
Part 9: More Soundloop Tweaks
Part 10: Simple PCM/Wavetable Synthesis
Part 11: Sound Tricks - Noise, Phasing, SID Sound, Earth Shaker, Duty Modulation
Part 12: Synthesizing Basic Waveforms: Rectangle, Triangle, Saw
Part 1: The Basics
Method 1 uses a synthesis procedure called Pulse Frequency Modulation (PFM) at it's heart. Because of the thin, razor-like pulses it produces, PFM is also known as the "pin pulse method". It is used in many engines like Octode, Qchan, Special FX/Fuzz Click, or Huby. The approach allows for mixing of many software channels even on slow hardware, but usually does not reproduce bass frequencies very well.
Ok, let's take a look at how the method works. Assume we have the following variables:
counter1 - a counter which holds the frequency value for channel 1. On Spectrum, let's use register B.
counter2 - a counter which holds the frequency value for channel 2. On Spectrum, let's use register D.
backup1 - a copy of the initial value of counter1. On Spectrum, let's use register C.
backup2 - a copy of the initial value of counter2. On Spectrum, let's use register E.
state - the output state of channel 1, can be off (0) or on (1). On Spectrum, we'll use A.
timer - a counter which holds the note length. Let's use HL for that.
So, in order to synthesize our two software channels, we do the following:
PSEUDOCODE ZX SPECTRUM ASM
DISABLE INTERRUPTS di # running interrupts will throw off timing
soundLoop: soundLoop:
state := off xor a
DECREMENT counter1 dec b
IF counter1 == 0 THEN jr nz,skip1
state := on ld a,#10
counter1 := backup1 ld b,c
ENDIF skip1:
OUTPUT state1 out (#fe),a
state := off xor a
DECREMENT counter2 dec d
IF counter2 == 0 THEN jr nz,skip2
state := on ld a,#10
counter2 := backup2 ld d,e
ENDIF skip2:
OUTPUT state2 out (#fe),a
DECREMENT timer dec hl
IF timer != 0 THEN ld a,h \ or l
GOTO soundLoop jr nz,soundLoop
ELSE
ENABLE INTERRUPTS ei
EXIT ret
ENDIF
Method 2 is called Pulse Interleaving, or XOR method. It is used in engines like Tritone, Savage, Wham! The Music Box, and Phaser1. This method will generate a more classic chiptune sound with full square waves and good bass. The drawback of this approach however is that it is more limiting in terms of the number of channels that can be generated.
Assume we have the same variables as in example 1. However, this time we'll use the H register to keep track of state1, and L to keep track of state2. That means we can't use HL as our timer anymore. Well, luckily we have IX at our disposal as well.
In addition, we need a constant which holds a value that will toggle any output state between off and on. We'll call it ch_toggle. On Spectrum, a value of 10h or 18h will do the trick.
PSEUDOCODE ZX SPECTRUM ASM
state1 := off ld h,0
state2 := off ld l,0
DISABLE INTERRUPTS di
soundLoop: soundLoop:
DECREMENT counter1 dec b
ld a,h ; load state1
IF counter1 == 0 THEN jr nz,skip1
state1 := state1 XOR ch_toggle xor #10 \ ld h,a
counter1 := backup1 ld b,c
ENDIF skip1:
OUTPUT state1 out (#fe),a
DECREMENT counter2 dec d
ld a,l ; load state2
IF counter2 == 0 THEN jr nz,skip2
state2 := state2 XOR ch_toggle xor #10 \ ld l,a
counter2 := backup2 ld d,e
ENDIF skip2:
OUTPUT state2 out (#fe),a
DECREMENT timer dec ix
IF timer != 0 THEN ld a,ixh \ or ixl
GOTO soundLoop jr nz,soundLoop
ELSE
ENABLE INTERRUPTS ei
EXIT ret
ENDIF
A note those willing to try this on ZX Spectrum - beware that the code needs to run from uncontended RAM. Running from contended RAM (ie. any address below 8000h) will completely destroy the routine's timing, producing random screeching noises instead of recognizable tones.
And that's all for part one, if you have any questions feel free to post them here.
984 2015-07-13 16:14:18
Re: 1-Bit Forum Music Compo 2015 (12 replies, posted in General Discussion)
Yeah, good to have you aboard. Also, welcome to teh Forum
985 2015-07-12 19:32:10
Topic: 1-Bit Forum Music Compo 2015 (12 replies, posted in General Discussion)
Here we go, the 1-Bit Forum Music Competition 2015 is open for submissions now! There are five categories, of course you're welcome to submit works to each of them.
General Rules
Any editor/routine is allowed, you can even write a new one if you like.
Works must be unreleased, and may not be published before the end of the compo.
Original works only, covers are not allowed.
Submissions must be anonymous (ie. no author names in source, binary, or mp3 tags).
Submit works in emulator format (.tap, .sna, .xex, etc.), and also provide mp3 renders for all your works.
For each entry, provide a seperate ID/readme file with info on author, title, tools used, platform, and how to run your entry on emulator/hardware.
Categories that receive less than 3 entries may be dropped or merged into the Wild category.
By submitting, you agree that your works will be made available for free download after the contest.
Only registered members of the 1-Bit Forum may vote.
UPDATE: NEW DEADLINE: Sept. 13th, 2015
Send your submissions to 1bitcompo AT randomflux DOT info.
Please don't send mp3 renders directly, but upload them to a file hoster instead and provide a link in your submission email.
CATEGORIES:
1-bit Classic
Write music for ZX Spectrum beeper and/or Atari 8bit GTIA. Maximum 2 submissions per author.
1-bit Alternative
Write music for any 1-bit platform of your choice, including but not limited to PC Speaker, Apple hooter, ZX81, calculators, Apogee, Channel F.
Maximum 1 submission per platform per author.
1-bit Wild
The category for "fake" 1-bit, made with VSTis, DSSIs, samples, etc. Anything goes as long as it sounds 1-bit. Max. 1 work per author.
1-bit 1K
Write a 1-bit tune that fits into one kilobyte. Works on any platform are accepted, maximum 2 submissions per author.
Maximum uncompressed binary size (ie. size of the player code + song data) = 1024 byte. Headers/loaders etc. don't count towards the file size.
Please submit an additional .bin file along with the usual tap/sna/xex.
1-bit Code
Write a new 1-bit routine for a platform of your choice. You can submit as many entries as you want to this category. Submissions don't need to be anonymous, in case you're worried someone's going to steal the code.
Submission format is plaintext .asm. Provide a short track demonstrating the capabilities of your routine (binary/emulator format + mp3 render). In the info file, state the specifications of your routine. Providing an editor/converter is not required, however it may positively influence your score if you do.
986 2015-07-12 13:04:29
Re: plans for a 1-bit forum contest (16 replies, posted in General Discussion)
Yes, that's indeed the point. Well, one of them at least
987 2015-07-12 12:08:49
Re: found on the web (1 replies, posted in General Discussion)
Yes, Jredd rulez. Even though this one is a bit too much on the happy side for me
988 2015-07-12 12:07:58
Re: plans for a 1-bit forum contest (16 replies, posted in General Discussion)
So I take it we'll have at least 3 entries for the 1K category? Alright then, I'll add it to the compo!
989 2015-07-10 10:57:57
Re: plans for a 1-bit forum contest (16 replies, posted in General Discussion)
I don't know if having several categories would be successful, but I'd like to give it a try I'd give a rather generous deadline, so people have enough time to dig a bit into the non-Spectrum tools.
Was even thinking about adding another category for 1K size limited tunes, so the "tiny" engines like Huby and ntropic get some love. Though that might indeed be overkill...
990 2015-07-07 22:45:20
Re: 1bit web radio (10 replies, posted in Sinclair)
Cool! And I should do some more conversions as well. I just never get around to it, my life is mostly code, eat, sleep, repeat these days.
991 2015-07-07 22:43:16
Re: testing some new tricks... (7 replies, posted in Sinclair)
@Shiru, I'd say yours is less noisy at low volumes, though still more noisy than I expected. I'm also surprised that the timbre changes just as much as with the phase shifting approach. Seems with the right ratios, some very interesting timbre effects can be created.
@AtariTufty: I'd love to put it in ntropic, along with proper 16-bit frequency counters. However in order to do so I'd need to build a few new registers into the Z80... So it'll probably really just become a new engine eventually.
992 2015-07-07 11:19:46
Topic: plans for a 1-bit forum contest (16 replies, posted in General Discussion)
Yeah, it's about time and I'm intending to launch it shortly, but before I do that I'd like to hear if you folks have any special requests/ideas for it.
My idea is to have 3 categories - Speccy+GTIA (think it makes sense to combine it into one category due to similarities in sound), Alternative Platforms (bascially anything that is not Speccy or Atari 8bit), and Code (aka write a new 1-bit engine). Well, that's the plan so far. What do you folks think? Considering Shiru's recent release, maybe we should add a "fake1bit" category as well?
993 2015-07-07 11:03:44
Re: testing some new tricks... (7 replies, posted in Sinclair)
@garvalf: It's an entirely new engine. Or rather, it will be eventually, as it still needs quite a bit of improvement and I don't really have the time to work on it these days.
@Shiru: Hehe no, this is quite different. Imagine you have two output states per channel. Now, if you inverse the phases of those outputs, you will hear - nothing. Which is logical, because one of the outputs will always be low and the other will always be high, so in combination the output state for that channel doesn't change. Well, I guess you can already deduce where this is going Shift the phase for one of the ouputs (ie start counting not at 0, but at #4000 or whatever) and voila. It also works with duty cycles other than 50:50, though then volume control gets more limited.
Overall I think the method you propose might be better sounding, but I somehow like this little trick
994 2015-07-06 20:30:16
Topic: testing some new tricks... (7 replies, posted in Sinclair)
Trying to tackle the good old "volume control" problem. Think I might have found something...
995 2015-07-06 09:20:06
Re: upcoming beeper compos (136 replies, posted in Sinclair)
Now now, 2nd place, not bad Congratz!
996 2015-07-02 16:13:45
Re: Dat Fuzz - Character set (3 replies, posted in Sinclair)
Iirc it might have been based on Skyscrap, but if so it's a heavily modified version. That .FZX is probably one big mess though.
997 2015-07-02 16:06:11
Re: 1bitstudio - a bundle of VST plugins (27 replies, posted in Other Platforms)
Whoa, that was unexpected. Well, I stopped using VSTs many years ago and I don't even have a host installed anymore, but I still think it's a neat idea. Looking forward to hear some sound examples made with it.
998 2015-07-01 15:59:02
Re: 1-bit music on GameBoy (7 replies, posted in Other Platforms)
Isn't there also a maximum to how fast the sound registers can be updated? I have it somewhere in the back of my head that access was quite slow.
As for beeper engines on the thing, I think the closest there is is still nitro2k1's "mystery rom", which uses the battery save function to flip the output state.
999 2015-07-01 15:50:07
Re: upcoming beeper compos (136 replies, posted in Sinclair)
Yeah, there were beeper tunes submitted to that one in the past, so that should be possible
1,000 2015-06-30 22:24:32
Re: upcoming beeper compos (136 replies, posted in Sinclair)
To quote the boss:
You can use any format for any year. Try to earn a badge!
I think that means you can do all beeper if you're so inclined. Thinking of also doing a few YM2149s myself, though.