Author Topic: klystrack!  (Read 15056 times)

0 Members and 1 Guest are viewing this topic.

Offline n00bstar

  • ZX 81
  • *
  • Posts: 22
  • Karma: 8
    • View Profile
klystrack!
« on: May 31, 2012 »
For some reason, a few week backs, I decided to check what was happening in the world of trackers. I've graduated from trackers to actual 'real' studio stuff years ago, but tracking will still always have a big warm fluffy place in my heart. So I've found the usual assortment of softwares, from clones of FT2 and IT to trackers that support all the VSTs in the world and dice your veggies and takes your kids to school and all that. All in all, it was a fairly disappointing experience. No scene spirit anywhere.. just VSTs and commercial products. That is, until I added the magic word to my Googling: Chiptune!

On top of a long list of only 1 item came: klystrack!

So heading over there and downloading this gizmo, I fell in love. The scene-cred is very high with this one, it looks like it was made in the 90s, it's fully open source, great developer support and a very comprehensive manual/wiki.

Those of you who remember AHX on the Amiga will be riiight at home with Klystrack, it takes most of its cues from it down to the sequence editor using floating patterns of variable lengths etc.

There's a library for it should you want to use the synth engine for your own products or to playback .KT tracks.

If you've read this far and haven't yet googled it and downloaded it, then lemme at least do the first step to help you out: http://code.google.com/p/klystrack/


Offline energy

  • Amiga 1200
  • ****
  • Posts: 280
  • Karma: 25
    • View Profile
Re: klystrack!
« Reply #1 on: May 31, 2012 »
Very good work. :clap:
Is there a replay routine available?
coding: jwasm,masm
hobby: www.scd2003.de

Offline Pot Noodle

  • Sponsor
  • Amiga 1200
  • *******
  • Posts: 271
  • Karma: 15
  • Computers have lots of memory but no imagination
    • View Profile
Re: klystrack!
« Reply #2 on: May 31, 2012 »
Good info n00bstar, Thanks for that I am glad you found the Amiga scene spirit you were looking for.  :goodpost:

Offline n00bstar

  • ZX 81
  • *
  • Posts: 22
  • Karma: 8
    • View Profile
Re: klystrack!
« Reply #3 on: May 31, 2012 »
@Energy, yes there is! Well... kind of, the code is there and the dev gives you all the info needed to compile your own. From what little I've toyed with the code, it is extremely efficient and has almost no CPU hit to speak of. Seeing as it takes me 8 hours of hard work and case of red bull to put a single sinescroller on screen, I don't think I'll be the one compiling it into a nifty little lib, but if anyone wants to give it a go (make me a blitz wrapper purdy pleez?) I will make music for all your projects out of sheer gratitude :D

Offline benny!

  • Senior Member
  • DBF Aficionado
  • ********
  • Posts: 4384
  • Karma: 228
  • in this place forever!
    • View Profile
    • bennyschuetz.com - mycroBlog
Re: klystrack!
« Reply #4 on: June 01, 2012 »
Looks awesome. Thanks for sharing!
[ mycroBLOG - POUET :: whatever keeps us longing - for another breath of air - is getting rare ]

Challenge Trophies Won:

Offline zawran

  • Sponsor
  • Pentium
  • *******
  • Posts: 909
  • Karma: 67
    • View Profile
Re: klystrack!
« Reply #5 on: June 01, 2012 »
I took a look at getting it to work with Bmax, and here is some code for you:

Code: [Select]
'
' load the KSND DLL into memory
'
Const KSND_DLL:String = "ksnd.dll"
Global g_hndDLL:Int
g_hndDLL = loadlibrarya(KSND_DLL)
If g_hndDLL = Null Or g_hndDLL = 0 Then
RuntimeError "Unable to find the file: "+KSND_DLL
End If

Private
' player calls
Global KSND_CreatePlayer:Byte Ptr(samplerate:Int)"Win32" = GetProcAddress(g_hndDLL,"KSND_CreatePlayer")
Global KSND_FreePlayer(kplayer:Byte Ptr)"Win32" = GetProcAddress(g_hndDLL,"KSND_FreePlayer")
Global KSND_PlaySong(kplayer:Byte Ptr,ksong:Byte Ptr,position:Int)"Win32" = GetProcAddress(g_hndDLL,"KSND_PlaySong")
Global KSND_Stop(kplayer:Byte Ptr)"Win32" = GetProcAddress(g_hndDLL,"KSND_Stop")
Global KSND_Pause(kplayer:Byte Ptr,state:Int)"Win32" = GetProcAddress(g_hndDLL,"KSND_Pause")
Global KSND_GetPlayPosition:Int(kplayer:Byte Ptr)"Win32" = GetProcAddress(g_hndDLL,"KSND_GetPlayPosition")
Global KSND_SetVolume(kplayer:Byte Ptr,volume:Int)"Win32" = GetProcAddress(g_hndDLL,"KSND_SetVolume")
' song calls
Global KSND_LoadSong:Byte Ptr(kplayer:Byte Ptr,path:Byte Ptr)"Win32" = GetProcAddress(g_hndDLL,"KSND_LoadSong")
Global KSND_LoadSongFromMemory:Byte Ptr(kplayer:Byte Ptr,mem:Byte Ptr,length:Int)"Win32" = GetProcAddress(g_hndDLL,"KSND_LoadSongFromMemory")
Global KSND_FreeSong(ksong:Byte Ptr)"Win32" = GetProcAddress(g_hndDLL,"KSND_FreeSong")
Global KSND_GetSongLength:Int(ksong:Byte Ptr)"Win32" = GetProcAddress(g_hndDLL,"KSND_GetSongLength")
Public

Type TKSND
Field player:Byte Ptr ' handle to active player
Field song:Byte Ptr ' handle to currently playing song

Function init:TKSND(samplerate:Int)
Local tmp:TKSND = New TKSND
tmp.player = KSND_CreatePlayer(samplerate)
Return tmp
End Function

' Player methods

Method play(position:Int=0)
KSND_PlaySong(Self.player,Self.song,position)
End Method

Method pause(state:Int=0)
' 1 = pause, 0 = continue
KSND_Pause(Self.player,state)
End Method

Method stop()
KSND_Stop(Self.player)
End Method

Method free()
KSND_FreePlayer(Self.player)
End Method

Method setVolume(volume:Int)
KSND_SetVolume(Self.player,volume)
End Method

Method getPlayPosition:Int()
Return KSND_GetPlayPosition(Self.player)
End Method

' Song methods

Method loadSong(path:String)
' check if a song is already loaded
If Self.song <> Null Then Self.freeSong()
Self.song = KSND_LoadSong(Self.player,path.ToCString())
If Self.song = Null Then
RuntimeError "Unable to load song: "+path
Else
Print "song loaded"
End If
End Method

Method loadSongFromMemory(mem:Byte Ptr,length:Int)
' check if a song is already loaded
If Self.song <> Null Then Self.freeSong()
Self.song = KSND_LoadSongFromMemory(Self.player,mem,length)
If Self.song = Null Then
RuntimeError "Unable to load song!"
Else
Print "song loaded"
End If
End Method

Method freeSong()
KSND_FreeSong(Self.song)
End Method

Method getSongLength:Int()
Return KSND_GetSongLength(Self.song)
End Method
End Type

And here is an example of using the above code:

Code: [Select]
SuperStrict
Incbin "obspatial.kt" ' this is for including the song in the exe

Include "TKSND.BMX"

Graphics 800,600


' prepare a player
Global music:TKSND = TKSND.init(44100)

' use this when loading song from bank
Global bk:TBank = LoadBank("incbin::obspatial.kt") ' this loads the song into a bank
music.loadSongFromMemory(LockBank(bk),BankSize(bk))
bk = Null

' use this when loading song from disc
'music.loadSong("obspatial.kt")

' play the music
music.play()

Global mute:Int = 0

While Not KeyHit(KEY_ESCAPE)
Cls
Local sl:Int = music.getSongLength()
Local pp:Int = music.getPlayPosition()
DrawText("Song Length: "+sl,8,8)
DrawText("Play Position: "+pp,8,24)
If mute = 1 Then DrawText("MUTED",8,48)
' check for pause/continue
If KeyHit(KEY_P) Then music.pause(1)
If KeyHit(KEY_C) Then music.pause(0)
' check for mute/unmute
If KeyHit(KEY_M) Then
mute = 1-mute
If mute = 0 Then
music.setVolume(100)
Else
music.setVolume(0)
End If
End If
Flip
Wend
music.freeSong()
music.free()
End

The known bugs are that the method for getting the length of the song returns a wrong number in release mode, but works correct in debug mode. I am not really sure where the problem lies, but since it is not something that will prevent people from using the klystrack tunes in their productions I figured that I might as well release the code already. I hope someone finds it useful. Remember to copy the ksnd.dll file to your project folder.

Offline n00bstar

  • ZX 81
  • *
  • Posts: 22
  • Karma: 8
    • View Profile
Re: klystrack!
« Reply #6 on: June 01, 2012 »
!!!!!!!!!!!

You rock sir. Tonight when you come home, your wife will be gold plated and your car will have spoilers on ALL FOUR SIDES. Damn right.

Now I have no choice, I have to switch to BMax! I was kinda of planning on it anyways (seeing as its s'posed to share a lot of syntax with Monkey) and this is a very good reason for it :)

But I'm at work and I only got b3d installed here. This is gonna be a long ass day before I get to play with this!

Offline zawran

  • Sponsor
  • Pentium
  • *******
  • Posts: 909
  • Karma: 67
    • View Profile
Re: klystrack!
« Reply #7 on: June 01, 2012 »
No problem, it was fun trying to get it to work.

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17409
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Re: klystrack!
« Reply #8 on: June 01, 2012 »
Cool deed Zawran :) K+
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Rbz

  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 2757
  • Karma: 493
    • View Profile
    • https://www.rbraz.com/
Re: klystrack!
« Reply #9 on: June 02, 2012 »
Very nice little tracker!

I've made a Freebasic wrapper using klystrack static library, examples included.
Purebasic version can be also easily made ;)

Challenge Trophies Won:

Offline jace_stknights

  • Amiga 1200
  • ****
  • Posts: 399
  • Karma: 32
  • PEEK & POKE are not MOVEM!
    • View Profile
    • ST Knights WebSite
Re: klystrack!
« Reply #10 on: June 02, 2012 »
As fast as the light!  :clap: Rbz :clap:
Challenge Trophies Won:

Offline zawran

  • Sponsor
  • Pentium
  • *******
  • Posts: 909
  • Karma: 67
    • View Profile
Re: klystrack!
« Reply #11 on: June 02, 2012 »
Seeing that RBZ has made a wrapper for freebasic using the static library so that you do not have to have the dll file in the folder, I thought that I would give it a go at making the wrapper do the same for Bmax. And after some thinkering I managed to get it to work.

Here is the new type for the wrapper:

Code: [Select]
Private
Extern "Os"
Function KSND_CreatePlayer:Byte Ptr(samplerate:Int)"C"
Function KSND_FreePlayer(kplayer:Byte Ptr)"C"
Function KSND_PlaySong(kplayer:Byte Ptr,ksong:Byte Ptr,position:Int)"C"
Function KSND_Stop(kplayer:Byte Ptr)"C"
Function KSND_Pause(kplayer:Byte Ptr,state:Int)"C"
Function KSND_GetPlayPosition:Int(kplayer:Byte Ptr)"C"
Function KSND_SetVolume(kplayer:Byte Ptr,volume:Int)"C"
' song calls
Function KSND_LoadSong:Byte Ptr(kplayer:Byte Ptr,path:Byte Ptr)"C"
Function KSND_LoadSongFromMemory:Byte Ptr(kplayer:Byte Ptr,mem:Byte Ptr,length:Int)"C"
Function KSND_FreeSong(ksong:Byte Ptr)"C"
Function KSND_GetSongLength:Int(ksong:Byte Ptr)"C"
End Extern
Public

Type TKSND
Field player:Byte Ptr ' handle to active player
Field song:Byte Ptr ' handle to currently playing song

Function init:TKSND(samplerate:Int)
Local tmp:TKSND = New TKSND
tmp.player = KSND_CreatePlayer(samplerate)
Return tmp
End Function

' Player methods

Method play(position:Int=0)
KSND_PlaySong(Self.player,Self.song,position)
End Method

Method pause(state:Int=0)
' 1 = pause, 0 = continue
KSND_Pause(Self.player,state)
End Method

Method stop()
KSND_Stop(Self.player)
End Method

Method free()
KSND_FreePlayer(Self.player)
End Method

Method setVolume(volume:Int)
KSND_SetVolume(Self.player,volume)
End Method

Method getPlayPosition:Int()
Return KSND_GetPlayPosition(Self.player)
End Method

' Song methods

Method loadSong(path:String)
' check if a song is already loaded
If Self.song <> Null Then Self.freeSong()
Self.song = KSND_LoadSong(Self.player,path.ToCString())
If Self.song = Null Then
RuntimeError "Unable to load song: "+path
Else
Print "song loaded"
End If
End Method

Method loadSongFromMemory(mem:Byte Ptr,length:Int)
' check if a song is already loaded
If Self.song <> Null Then Self.freeSong()
Self.song = KSND_LoadSongFromMemory(Self.player,mem,length)
If Self.song = Null Then
RuntimeError "Unable to load song!"
Else
Print "song loaded"
End If
End Method

Method freeSong()
KSND_FreeSong(Self.song)
End Method

Method getSongLength:Int()
Return KSND_GetSongLength(Self.song)
End Method
End Type

And here is a new example to show how it is called:

Code: [Select]
SuperStrict
Import "-lksndstatic"

Incbin "Paranoimia (Suntronic).kt" ' this is for including the song in the exe

Include "TKSNDstatic.BMX"

Graphics 800,600


' prepare a player
Global music:TKSND = TKSND.init(44100)

' use this when loading song from bank
Global bk:TBank = LoadBank("incbin::Paranoimia (Suntronic).kt") ' this loads the song into a bank
music.loadSongFromMemory(LockBank(bk),BankSize(bk))
bk = Null

' use this when loading song from disc
'music.loadSong("obspatial.kt")

' play the music
music.play()

Global mute:Int = 0

While Not KeyHit(KEY_ESCAPE)
Cls
Local sl:Int = music.getSongLength()
Local pp:Int = music.getPlayPosition()
DrawText("Song Length: "+sl,8,8)
DrawText("Play Position: "+pp,8,24)
If mute = 1 Then DrawText("MUTED",8,48)
' check for pause/continue
If KeyHit(KEY_P) Then music.pause(1)
If KeyHit(KEY_C) Then music.pause(0)
' check for mute/unmute
If KeyHit(KEY_M) Then
mute = 1-mute
If mute = 0 Then
music.setVolume(100)
Else
music.setVolume(0)
End If
End If
Flip
Wend
music.freeSong()
music.free()
End

So instead of copying the dll file to your project folder, you copy the following file "libksndstatic.a" to the "lib" folder in your Bmax installation folder.

Using this version will pack the player code into your exe and you no longer need the dll file. Please note that new line <Import "-lksndstatic"> at the top of the example. You will have to have that line in the top of your project code along with what other imports you have. It is the line that loads the c library.

Offline Pot Noodle

  • Sponsor
  • Amiga 1200
  • *******
  • Posts: 271
  • Karma: 15
  • Computers have lots of memory but no imagination
    • View Profile
Re: klystrack!
« Reply #12 on: June 02, 2012 »
Well done guys, I don't think n00bstar will need all that Red Bull now!  :goodpost:

Offline TinDragon

  • Pentium
  • *****
  • Posts: 644
  • Karma: 24
    • View Profile
    • J2K's blog
Re: klystrack!
« Reply #13 on: June 02, 2012 »
For the Bmax users, if you dont feel like copying the libksndstatic.a into your bmax lib folder and would rather have it in the projects folder (I know some people prefer this) then you can do so, just change the import line from
Code: [Select]
Import "-lksndstatic"to
Code: [Select]
Import "libksndstatic.a"
Nice job on wrapping this player guys, now lets seem some of you creative types make some tunes in it :D

Offline n00bstar

  • ZX 81
  • *
  • Posts: 22
  • Karma: 8
    • View Profile
Re: klystrack!
« Reply #14 on: June 03, 2012 »
music?

three tracks included, free for all to use in dbf-related prods :)


Offline padman

  • Senior Member
  • Pentium
  • ********
  • Posts: 990
  • Karma: 260
    • View Profile
Re: klystrack!
« Reply #15 on: June 05, 2012 »
Quote
Purebasic version can be also easily made ;)

Word. PB wrapper & example attached. ;D

I didn't do too much testing, but the main functions work on my WinXP machine...

Enjoy!


Challenge Trophies Won:

Offline Shockwave

  • good/evil
  • Founder Member
  • DBF Aficionado
  • ********
  • Posts: 17409
  • Karma: 498
  • evil/good
    • View Profile
    • My Homepage
Re: klystrack!
« Reply #16 on: June 05, 2012 »
K+
Shockwave ^ Codigos
Challenge Trophies Won:

Offline Kirl

  • Senior Member
  • Pentium
  • ********
  • Posts: 1217
  • Karma: 230
    • View Profile
    • Homepage
Re: klystrack!
« Reply #17 on: June 05, 2012 »
:clap: @ all
www.kirl.nl
Challenge Trophies Won:

Offline n00bstar

  • ZX 81
  • *
  • Posts: 22
  • Karma: 8
    • View Profile
Re: klystrack!
« Reply #18 on: June 05, 2012 »
Very good work people!

Yknow, I think that, with's you's people's permissions'ses of course, we should be contacting klystrack's author and have him host these wrappers alongside the software, it would certainly give a bigger incentive to interested parties who might not have the know how to wrap the lib and can't afford the real estate of downmixing to wav.

Also, I'm a man of my word, I re-extend the offer for one (1) free and personalized klystrack song to anyone who develops something for my favorite little tracker :)

Offline jace_stknights

  • Amiga 1200
  • ****
  • Posts: 399
  • Karma: 32
  • PEEK & POKE are not MOVEM!
    • View Profile
    • ST Knights WebSite
Re: klystrack!
« Reply #19 on: June 06, 2012 »
 :clap: well done Pad!
Challenge Trophies Won: