Author Topic: Drum Machine Prototype  (Read 9425 times)

0 Members and 1 Guest are viewing this topic.

Offline TrialAndTerror

  • Newbie
  • Posts: 11
  • Kick The Can
    • View Profile
    • T&T Ware
Re: Drum Machine Prototype
« Reply #15 on: April 14, 2020, 10:27:14 pm »
Great program! Thank you Dav. It helps me out when recording some musical ideas.
Very inspiring.

I haven't looked into the code but I have a question:
Can you make it run 3/4 too?
It's an essential feature for a drum machine.

T&T
« Last Edit: April 14, 2020, 10:43:55 pm by TrialAndTerror »

Offline QBExile

  • Newbie
  • Posts: 9
    • View Profile
Re: Drum Machine Prototype
« Reply #16 on: April 15, 2020, 06:46:15 am »
Great program Dav. Love the concept and implementation and coding style.

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Drum Machine Prototype
« Reply #17 on: April 15, 2020, 06:06:02 pm »
Hi Dav
I can say that this new version is a good improvement...and it runs well also in Kubuntu!


Great job
Programming isn't difficult, only it's  consuming time and coffee

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Drum Machine Prototype
« Reply #18 on: April 16, 2020, 10:58:05 am »
@QBExile: Thanks!

@TrialAndTerror: Not currently, but I will work on implementing other meters like 3/4.

@TempodiBasic: Thanks for the Linux report.  I was thinking about using Win API's for some things planned, but I will put that off to keep it Linux friendly.

- Dav

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Drum Machine Prototype
« Reply #19 on: April 16, 2020, 02:08:39 pm »
Sorry Dav, I march to the beat of a different drummer...

 
Pete-Rules.jpg
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Drum Machine Prototype
« Reply #20 on: April 16, 2020, 04:56:22 pm »
I started working on saving to WAV format for this program. It will take a few days, I still have little time.

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Drum Machine Prototype
« Reply #21 on: April 17, 2020, 08:08:01 am »
Cool, Petr!  Then we can all WAV at Pete while he marches.

I tried to draw a reply Pete, but I couldn't fit in anything funny - now I just gotta expand the playing grid.

- Dav

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Drum Machine Prototype
« Reply #22 on: April 17, 2020, 12:07:03 pm »
No seriously Dav, I ran your prog on my computer, and that's just the way it displayed itself! Of course, I just had a Windows update installed. Anyway, sorry to cause you more work, but even sorrier if it takes your time away form creating more cool stuff, like this, to share. Nice work, as always!

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Drum Machine Prototype
« Reply #23 on: April 17, 2020, 04:36:22 pm »
So, the program WAV is coming out, but I have significant problems with time synchronization. Somehow I can't figure out how to correctly count the position of the beginning of the sound on the timeline using the TEMPO parameter. Next, it looks like setting the sound level for _SNDVOL in the range of 0 - 1 (even if the original of the program has values above 1) will have to adapt for WAV. Today I am very tired, I will continue tomorrow. Here is one of the first outputs.

 

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Drum Machine Prototype
« Reply #24 on: April 18, 2020, 10:41:52 am »
The wav sounds ok.  I sure appreciate your efforts helping my programs. 

- Dav

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Drum Machine Prototype
« Reply #25 on: April 18, 2020, 03:10:57 pm »
Hi.

I am very pleased to announce the completion of my resolution. You can now save the SAV file that creates this wonderful DavĀ“s  program using my utility as a WAV file. The only thing he needs to fine-tune is the volume level of some instruments, but I think, Dav can handle it better, because I absolutely do not have musical hearing.

To run the program, you need all the tools converted to WAV and the SAV file that is the output of Dave's drummachine program. All this, including the source code, is attached.

Code: QB64: [Select]
  1. 'Dav SAV to WAV utility
  2. SCREEN _NEWIMAGE(100, 30, 0)
  3.  
  4. FileName$ = "drummachine.sav"
  5.  
  6.  
  7.  
  8.  
  9. TYPE Snd
  10.     Left AS SINGLE
  11.     Right AS SINGLE
  12. REDIM SHARED OutputSound(-1) AS Snd
  13.  
  14. TYPE OtpSndHelper
  15.     Offset_Start AS LONG
  16.     Offset_End AS LONG
  17. REDIM SHARED OTP(1) AS OtpSndHelper
  18.  
  19.  
  20.  
  21. IF _FILEEXISTS(FileName$) THEN
  22.     DIM tempo AS INTEGER, buttons AS INTEGER
  23.     FF = FREEFILE
  24.     OPEN FileName$ FOR BINARY AS #FF
  25.     GET #FF, , tempo
  26.     GET #FF, , buttons
  27.     DIM s1(buttons) AS INTEGER
  28.     GET #FF, , s1()
  29.     PRINT "Error loading DAV's SAV file.": SYSTEM
  30.  
  31. DIM Sounds(1 TO 32, 1 TO 16) AS INTEGER
  32. y = 1
  33. x = 0
  34.  
  35. 'converse from 1D array to 2D array (uncompatible with QB64 logic, IS NOT POSSIBLE read Sounds() direct with GET for the same data order!)
  36. FOR a = 0 TO 511
  37.     IF x = 32 THEN y = y + 1: x = 0
  38.     x = x + 1
  39.     Sounds(x, y) = s1(a)
  40.  
  41. PRINT "Loading DAV's SAV file..."
  42. PRINT "Tempo:"; tempo
  43. PRINT "Buttons:"; buttons
  44. PRINT "Patterns:"
  45.  
  46. 'test
  47. FOR y = 1 TO 16
  48.     PRINT
  49.     FOR x = 1 TO 32
  50.         PRINT Sounds(x, y);
  51. NEXT x, y
  52.  
  53. PRINT "Loaded sounds data table. Press key..."
  54.  
  55.  
  56. PRINT "Loading WAV samples"
  57.  
  58. DIM Samples(1 TO 16) AS LONG
  59. RESTORE Samples
  60. FOR LoadSamples = 1 TO 16
  61.     READ s$
  62.     Sample$ = "wavsamples\" + s$ + ".wav"
  63.     Samples(LoadSamples) = WAVtoRAW(Sample$)
  64.     PRINT "Loaded sample: "; s$
  65. PRINT "Total track time:"; 3 + 32 * (60 / 4 / tempo); "seconds (3 seconds added extra to end)."
  66.  
  67.  
  68. 'DATA samples order MUST be in the same order as in drummachine.bas on left (from top to bottom)
  69. Samples:
  70. DATA "crash","ride","hhopen","hhclosed","tomhigh","tommid","tomlow","snare","kick","cowbell","shaker","tamb","vibraslap","gong","triangleshort","clave"
  71.  
  72. 'Insert samples to time track
  73. DIM TimeTrack(1 TO 32, 1 TO 16) AS SINGLE
  74. REDIM newsound(44100 * 30) AS Snd
  75.  
  76.  
  77. DelayTime = 60 / 4 / tempo
  78. FOR y = 1 TO 16 '              rows
  79.     FOR x = 1 TO 32 '          column's
  80.         IF Sounds(x, y) THEN
  81.             TimeTrack(x, y) = DelayTime * x
  82.         END IF
  83. NEXT x, y
  84. PRINT "Time track done. Creating WAV content..."
  85.  
  86.  
  87.  
  88.  
  89. FOR row = 1 TO 16
  90.     FOR column = 1 TO 32
  91.         IF Sounds(column, row) THEN
  92.             lenght& = 44100 * TimeTrack(column, row) '          calculate lenght for track in BYTES: Time lenght * sample rate (44100 is used also in WAV header)
  93.             IF Sounds(column, row) = 1 THEN
  94.                 RESTORE status1
  95.                 FOR SearchVolume = 1 TO row
  96.                     READ vol 'INFO for DAV:  This is the same as your SUB PLAYBEAT. status1: is for "1" values
  97.                 NEXT
  98.  
  99.             END IF
  100.             IF Sounds(column, row) = 2 THEN
  101.                 RESTORE status2
  102.                 FOR SearchVolume = 1 TO row
  103.                     READ vol 'INFO for DAV:  This is the same as your SUB PLAYBEAT. status1: is for "2" values
  104.                 NEXT
  105.  
  106.             END IF
  107.             RAWCOPY Samples(row), newsound(), lenght&, vol '    copy sounds to correct places (in time) to array (if on this places is sound, is content
  108.         END IF '                                                mixed in SUB RAWCOPY, RAWCOPY in this program is updated!)
  109.     NEXT
  110.  
  111. RealLenght newsound(), DelayTime * 32 + 3 ' (32 samples + 3 seconds lenght extra)
  112. PRINT "Done. Saving file drummachine.wav... (16 bit stereo, 44100)"
  113. SAVESOUND16S newsound(), "drummachine.wav"
  114. PRINT "Operation comleted. SAV file is now saved as WAV music file."
  115.  
  116.  
  117.  
  118. 'DAV, here you can reset VOLUME values (if sound in WAV for sample is too loud, or too silent)
  119. 'values are rewrited from original DAV's drummachine.bas program
  120. status1: '1 in sav table
  121. DATA 6,5,5,1,9,9,9,1,1,.3,.6,1,.1,.1,.3,.6
  122. status2: '2 in sav table
  123. DATA .2,.2,.15,.2,.1,.1,.1,.1,.1,.2,.1,.1,.05,.03,.3,.02
  124.  
  125. FUNCTION WAVtoRAW (file$) '                              Function load WAV file (this just 16bit, stereo format) and load it to array as RAW.
  126.     TYPE head
  127.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  128.         size AS LONG '              4 bytes  (?E??)
  129.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  130.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  131.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  132.         format AS STRING * 2 '      2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  133.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  134.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  135.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  136.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  137.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  138.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  139.     END TYPE '                     40 bytes  total
  140.     DIM H AS head
  141.     ch = FREEFILE
  142.  
  143.     IF _FILEEXISTS(file$) THEN OPEN file$ FOR BINARY AS #ch ELSE PRINT file$; " not found": SLEEP 2: SYSTEM
  144.     GET #ch, , H
  145.  
  146.     block = H.Block
  147.     RATE = H.rate
  148.     chan = H.channels
  149.     bits = H.Bits
  150.  
  151.     SEEK #ch, Find_data_area(file$)
  152.  
  153.     OTP_Size = UBOUND(otp)
  154.     OTP(OTP_Size).Offset_Start = UBOUND(outputsound) + 1
  155.  
  156.     DO WHILE NOT EOF(ch)
  157.         IF bits = 16 AND chan = 2 THEN
  158.             REDIM lefi AS INTEGER, righi AS INTEGER
  159.             GET #ch, , lefi
  160.             GET #ch, , righi
  161.             lef = lefi / 65535
  162.             righ = righi / 65535
  163.         END IF
  164.  
  165.         IF RATE > 44100 THEN frekvence = RATE ELSE frekvence = 44100
  166.  
  167.         oss = UBOUND(OutputSound)
  168.         REDIM _PRESERVE OutputSound(oss + (frekvence / RATE)) AS Snd
  169.  
  170.         FOR plll = 1 TO frekvence / RATE
  171.             OutputSound(oss + plll).Left = lef
  172.             OutputSound(oss + plll).Right = righ
  173.         NEXT plll
  174.  
  175.         DO WHILE _SNDRAWLEN > 0: LOOP: REM comment this
  176.     LOOP
  177.  
  178.     OTP(OTP_Size).Offset_End = UBOUND(outputsound)
  179.     REDIM _PRESERVE OTP(OTP_Size + 1) AS OtpSndHelper
  180.     CLOSE ch
  181.     WAVtoRAW = OTP_Size
  182.  
  183. FUNCTION Find_data_area (handle$)
  184.     REDIM D AS STRING * 1024
  185.     ff = FREEFILE
  186.     OPEN handle$ FOR BINARY AS #ff
  187.     GET #ff, 1, D$
  188.     CLOSE #ff
  189.     Find_data_area = INSTR(1, D$, "data") + 8
  190.  
  191. SUB RAWCOPY (handle, arr() AS Snd, position AS LONG, Volume AS SINGLE)
  192.     SoundLenghtInBytes = OTP(handle).Offset_End - OTP(handle).Offset_Start
  193.     IF UBOUND(arr) < UBOUND(arr) + SoundLenghtInBytes THEN REDIM _PRESERVE arr(UBOUND(arr) + SoundLenghtInBytes) AS Snd
  194.     DIM rc AS LONG, OTPS AS LONG
  195.     OTPS = OTP(handle).Offset_Start
  196.     FOR rc = position TO position + SoundLenghtInBytes
  197.  
  198.         IF arr(rc).Left THEN OutLeft = (arr(rc).Left + (OutputSound(OTPS).Left) * Volume) / 1 ELSE OutLeft = OutputSound(OTPS).Left * Volume
  199.         IF arr(rc).Right THEN OutRight = (arr(rc).Right + (OutputSound(OTPS).Right) * Volume) / 1 ELSE OutRight = OutputSound(OTPS).Right * Volume
  200.  
  201.         IF OutLeft > .75 THEN OutLeft = .9
  202.         IF OutLeft < -.75 THEN OutLeft = -.9
  203.  
  204.         IF OutRight > .75 THEN OutRight = .9
  205.         IF OutRight < -.75 THEN OutRight = -.9
  206.  
  207.         arr(rc).Left = OutLeft
  208.         arr(rc).Right = OutRight
  209.         OTPS = OTPS + 1
  210.     NEXT rc
  211.  
  212. SUB RealLenght (arr() AS Snd, time AS SINGLE)
  213.     Size = time * _SNDRATE
  214.     REDIM _PRESERVE arr(Size) AS Snd
  215.  
  216. SUB SAVESOUND16S (arr() AS Snd, file AS STRING)
  217.  
  218.     TYPE head16
  219.         chunk AS STRING * 4 '       4 bytes  (RIFF)
  220.         size AS LONG '              4 bytes  (file size)
  221.         fomat AS STRING * 4 '       4 bytes  (WAVE)
  222.         sub1 AS STRING * 4 '        4 bytes  (fmt )
  223.         subchunksize AS LONG '      4 bytes  (lo / hi), $00000010 for PCM audio
  224.         format AS INTEGER '         2 bytes  (0001 = standard PCM, 0101 = IBM mu-law, 0102 = IBM a-law, 0103 = IBM AVC ADPCM)
  225.         channels AS INTEGER '       2 bytes  (1 = mono, 2 = stereo)
  226.         rate AS LONG '              4 bytes  (sample rate, standard is 44100)
  227.         ByteRate AS LONG '          4 bytes  (= sample rate * number of channels * (bits per channel /8))
  228.         Block AS INTEGER '          2 bytes  (block align = number of channels * bits per sample /8)
  229.         Bits AS INTEGER '           2 bytes  (bits per sample. 8 = 8, 16 = 16)
  230.         subchunk2 AS STRING * 4 '   4 bytes  ("data")  contains begin audio samples
  231.         lenght AS LONG '            4 bytes  Data block size
  232.     END TYPE '                     44 bytes  total
  233.     DIM H16 AS head16
  234.     ch = FREEFILE
  235.  
  236.     H16.chunk = "RIFF"
  237.     H16.size = 44 + UBOUND(arr) * 4 'two channels, it create 16 bit, stereo wav file, one sample use 2 bytes to one channel
  238.  
  239.     H16.fomat = "WAVE"
  240.     H16.sub1 = "fmt "
  241.     H16.subchunksize = 16
  242.     H16.format = 1
  243.     H16.channels = 2
  244.     H16.rate = 44100
  245.     H16.ByteRate = 44100 * 2 * 16 / 8
  246.     H16.Block = 4
  247.     H16.Bits = 16
  248.     H16.subchunk2 = "data"
  249.     H16.lenght = UBOUND(arr) * 4
  250.     IF _FILEEXISTS(file$) THEN KILL file$
  251.  
  252.     OPEN file$ FOR BINARY AS #ch
  253.     PUT #ch, , H16
  254.     DIM LeftChannel AS INTEGER, RightChannel AS INTEGER
  255.  
  256.     FOR audiodata = 0 TO UBOUND(arr)
  257.         LeftChannel = arr(audiodata).Left * 32768
  258.         RightChannel = arr(audiodata).Right * 32768
  259.  
  260.         PUT #ch, , LeftChannel
  261.         PUT #ch, , RightChannel
  262.     NEXT
  263.     CLOSE ch
  264.  

This is known music for Dav's drummachine testers:
 


Is recorded sound in WAV file too fast or too slow? Go to row 84 in source code and try this: DelayTime = 1.25 * 60 / 4 / tempo


Quote
I sure appreciate your efforts helping my programs.

Thank you, it's training and preparation for my own music editor. For example. Have you considered the possibility of different TEMPO values for individual music tracks, or only in some parts? It's just the thing I'm thinking about.
* DavS SAV to WAV.zip (Filesize: 2.28 MB, Downloads: 213)
« Last Edit: April 19, 2020, 06:56:46 am by Petr »

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Drum Machine Prototype
« Reply #26 on: April 19, 2020, 05:56:44 pm »
Wow, great work, Petr!  What a great way to do it.  It sounds great - I'll play around with it and see IF there's anything I could add.  I think we could add a Export to WAV option in the drum machine with your tool.  Many Thanks!

About different TEMPO for individual tracks, I haven't considered it, but I'm open to it.  Right now I'm trying to come up with allowing set pattern lengths, and changing meters (1/2, 34,etc). 

I have a couple of other coding projects taking most of my attention at the moment (and working in the garden), but I will be continue improving the drum machine.  If I get a new job though (desperately  looking..) my coding projects will be slowing down.

You are a good coder.

- Dav
« Last Edit: April 19, 2020, 06:06:49 pm by Dav »

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Drum Machine Prototype
« Reply #27 on: April 19, 2020, 06:26:02 pm »
Petr certianly is a good coder, especially when, and I'm assuming, English is not his primary language. Actually, a lot of the regulars, who kept the faith with QBasic instead of bailing to FreeBasic, are good enough that if we ever all teamed up together, Bill gates would be working for us... as our Uber driver, of course.

Wow, now we have sight and sound. I'll have to link TheBOB to this thread, as he is quite the music lover.

Now step on it Gates, you dumbass bastard. I'm late for my Social Distancing class.

Pete
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Drum Machine Prototype
« Reply #28 on: April 21, 2020, 11:18:12 am »
Hi Dav,

I'm not a musician, so my ask:

What do you mean by changing meters? Do you want to change the music sample length? Does this mean, for example, that the sound of a drum strike is slower or faster? This is also a solvable problem in QB64, just don't know if I understand it correctly. Or is it the speed at which the sound should be played?  If I know the problem, I can try to find a solution.


Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Drum Machine Prototype
« Reply #29 on: April 21, 2020, 11:19:59 am »
Pete: There in QB64 forum are many better programmers than I am.  But thanks :)