Foobler notes - 3 - "Techno in a line of C"

I was remembering a cool Linux trick, where you could echo a C code one-liner at the compiler, then run the binary, piping the output right into aplay. Music of a sort would come out, perhaps 8-bit techno.

Maybe…

echo “main(t){for(t=0;;t++)putchar(t*(((t>>12)|(t>>8))&(63&(t>>4))));}” | gcc; ./a.out | aplay

I saw this written up in 2011, over at…

Of course, this is now just some HTML5 page now!

Ooh, look, you can change the formula on the fly!

So, of course my question is…

Can this be done on the PicoCalc in Basic?

Bonus points if it isn’t writing files to stash the sound, if it runs forever, and if it uses the built-in speakers!

3 Likes

So I stared at the WebMite Basic manual for a while, looking to see if there was any way to just fling bytes at the speaker.

You can play a WAV file. So, you could write a file, then play it.

But what is closer to just creating and flinging bits at a speaker?

Could you create a sample, then pack that into an array that PLAY SOUND expects?

DIM t as INTEGER
DIM a(4095) as INTEGER 
DIM b(1023) as INTEGER

FOR t = 0 to 4095
  a(t) = (t  5 AND t >> 7) OR (t  * 3 AND (t * 4 >> 10))
NEXT t

MEMORY PACK a%(), b%(), 4096, 16
PLAY LOAD SOUND b%()
PLAY SOUND 1, “B”, U , 4000, 1
PAUSE 1000

…unfortunately, this didn’t work.

It’s just where I left off.

There’s probably a better way to do this?

2 Likes

I’m not sure about flinging bytes, but PLAY TONE and PLAY SOUND might be what you’re looking for?

1 Like

Flobber, that’s a really great and creative idea — creating a one-liner that outputs a kind of techno music. Try using the MMBasic command PULSE (PULSE pin, width — check the manual for details) on a pin where you have a speaker connected. I connected a servo to the PicoCalc using ‘PULSE’ and was able to control it. It works really well

Pulse-width modulation could also be interesting. The PWM command doesn’t work in MMBasic 5.09, but in version 6.0 you should give it a try — I haven’t tested it yet myself. I can easily imagine making a one-liner with an interesting audio output that fits on a single line of code. Give it a shot and post it here — I’ll also get a bit creative with it!

Gordon

Here is the PicoCalc Servo routine on YouTube:Servo video

2 Likes

Hi,

I used the weekend and, on the passenger seat during the drive back, worked a bit on the Bytebeat program. I’ll give you two approaches that work quite well.

The first one is output via GPIO to an external speaker , so you can directly output byte streams. That’s really a lot of fun and comes closest to the artistic concept of Bytebeats. Play yourself with the width of pulse and the pause time to get interesting beats. Almost a „onliner“

Do:Pulse 4,Abs(Sin(i/5)*200):i=i+1:Pause 50:Loop

SetPin 4,dout ’ connect speaker to pin 4 and ground of the PicoCalc

Do
Pulse 4,Abs(Sin(i/5)*200)
i=i+1
Pause 50
Loop

The second code is a kind of simulator with the internal speakers of the PicoCalc , where you can enter mathematical formulas—used in the Bytebeat scene—as both frequency and pause values.



'--- ByteBeat Demo for Clockwork/PicoMite ---

' Choose ONE formula for f, comment out
Do
'f = (t Mod 20)/5 + (t>>3) Mod 9'bird
'f = (t Mod 30)/3 + (t>>7) Mod 11'wobl
'f = (t*3 And t>>7) Mod 20 'space
'f = (t*t) Mod 50'emergency
'f = (t*9 And t>>4)'echo of death                         ' heavy pounding rhythm

  ' Output sound
  Play tone f*100, f*100

  ' Optional: draw pixels
  Pixel t/100, f*2+160

  ' Increase counter
  t = t + 1

  ' Pause rhythm, play also with it!
  Pause ((t Mod 16)/5) + ((t>>4) Mod 2)
  'Pause ((t*t) Mod 30)/10   ' alternative pause pattern

  ' Stop with key Q
  If Inkey$ = "q" Then End
Loop

I’ve attached some examples. You can select the example by commenting out the f= math algorithm.

If it’s okay with you, I’ll make a video about it for my YouTube channel.

Have fun bytebeating :slight_smile:

Gordon

4 Likes

‘Inc t’ is slightly faster than ‘t=t+1’ if speed is of the essence….

1 Like

I was thinking along similar lines, but I thought I could use a timer interrupt to stop SOUND from playing at regular intervals, load the next 4096 samples, and so on. I get something, but nothing like the originals, and not as sweet sounding @Gordons_Treehouse77 s version.

Setting sample to 1 does a complex sine sound wave at 440 Hz, which I just used to see how PLAY LOAD SOUND works, sample 2 and 3 are “algorithmic”. I plot the first 4096 samples.

It’s not quite right but a work in progress, perhaps someone can spot the issues.

Option base 0
Option explicit

Const BITS12 = (1<<12)
Const BITS8 = (1<<8)
Const SAMPLE_LENGTH=4096
Const k=50 'scale graph

Dim wdata%(SAMPLE_LENGTH-1)
Dim pwdata%(SAMPLE_LENGTH\4-1)
Dim i%, t%, amp, x, freq, vol
Dim x0,x1,y0,y1

'modify for different samples
' 1 = complex sine example
' 2 and 3 algorithmic waveforms
Dim integer sample=3

CLS

If sample=1 Then
  load_simple_waveform
Else
  load_waveform
End If
plot_waveform

'Do : Loop While Inkey$=""

vol=25
SetTick 1/freq*1000,play_sample
Do
  'do nothing
Loop
End

Sub play_sample
  Play stop
  Play load sound pwdata%()
  Play sound 1,B,U,freq,vol
  If sample=1 Then
    load_simple_waveform
  Else
    load_waveform
  End If
End Sub

Sub load_waveform
  Local integer z,i
  Local x,y
  freq = 2
  For i%=0 To SAMPLE_LENGTH-1
    If sample=2 Then
    z = t%*((t%>>12 Or t%>>8) And 63 And t%>>4)
    ElseIf sample=3 Then
      z = ((t%>>6) Or t% Or (t%>>16))*10 + ((t%>>11) And 7)
    End If
    wdata%(i%) = z And 255 'fit to 8BITS
    Inc t%
  Next i%

  ' shape the data to 12 bit values
  Math window wdata%(),0,BITS12,wdata%()

  ' pack the data down
  Memory pack wdata%(),pwdata%(),4096,16
End Sub

Sub load_simple_waveform
  Local integer x
  freq = 440
  amp=100
  For i%=0 To SAMPLE_LENGTH-1
    x = amp*Sin(2*Pi/SAMPLE_LENGTH*i%)
    x = x + amp*Sin(2*Pi*2/SAMPLE_LENGTH*i%)
    x = x + amp*Sin(2*Pi*4/SAMPLE_LENGTH*i%)
    wdata%(i%) = x
  Next i%

  ' shape the data to 12 bit values
  Math window wdata%(),0,BITS12,wdata%()

  ' pack the data down
  Memory pack wdata%(),pwdata%(),4096,16
End Sub

Sub plot_waveform
  Local x0,x1,y0,y1,i%
  x0=0
  y0=wdata%(0)/k+160
  Line 0,160,320,160,1,RGB(white)
  Line 0,160+BITS12/k,320,160+BITS12/k,1,RGB(white)
  For i%=1 To SAMPLE_LENGTH-1
    x1 = i%*320/SAMPLE_LENGTH
    y1 = wdata%(i%)/k+160
    Line x0,y0,x1,y1
    x0=x1
    y0=y1
  Next i%
End Sub                                                                             
1 Like