Giter Site home page Giter Site logo

lsdpack's Introduction

lsdpack

Records LSDj songs for .gbs conversion or use in stand-alone Game Boy ROMs. (E.g. your own music albums, demos, games...)

Building

Requires CMake, RGBDS and a C++ compiler. Exact build steps are platform dependent - see Running CMake

C++ CI with CMake C++ CI with CMake

Recording Songs

All songs must first be prepared so that they eventually stop with the HFF command. Place your .sav and .gb file in the same directory and run e.g. ./lsdpack.exe lsdj.gb to record the songs to lsdj.s. To record songs from several .gb files, add them all to the command line, like ./lsdpack.exe 1.gb 2.gb 3.gb.

Game Boy Sound System (GBS)

Create .gbs files using the commands below. For compatibility reasons, .gbs files should be below 512 kB, so each .gbs file will contain one song only.

# dump songs
./lsdpack.exe -g lsdj.gb

# assemble player
rgbasm -o player.o player.s

# assemble songs individually
rgbasm -o lsdj-1.o lsdj-1.s
rgbasm -o lsdj-2.o lsdj-2.s
...

# make one .gb file for each song
rgblink -o player-1.gb player.o lsdj-1.o
rgblink -o player-2.gb player.o lsdj-2.o
...

# create the final .gbs files, one by one
./makegbs.exe -t "Better Off Alone" -a "Alice Deejay" -c "(C) Violent Music 1997" player-1.gb
...

Playing Songs from Your Own Code

An example Game Boy player ROM can be built using RGBDS:

rgbasm -o boot.o boot.s
rgbasm -o player.o player.s
rgbasm -o lsdj.o lsdj.s
rgblink -o player.gb boot.o player.o lsdj.o
rgbfix -v -m 0x19 -p 0xff player.gb

player.s

Contains the player code. Following symbols are exported:

; IN: a = song number
; OUT: -
; SIDE EFFECTS: trashes af
;
; Starts playing a song. If a song is already playing,
; make sure interrupts are disabled when calling this.
;
LsdjPlaySong::

; IN: -
; OUT: -
; SIDE EFFECTS: changes ROM bank, trashes af
;
; Call this six times per screen update,
; evenly spread out over the screen.
;
LsdjTick::

; A table that holds the ROM position for each song.
; Each entry is 4 bytes big.
SongLocations::
SongLocationsEnd::

boot.s

An example for how to use the player. Displays CPU usage using raster bars. Pressing A skips to the next song.

Screenshot

How Does It Work?

lsdpack plays back LSDj songs using an emulated Game Boy Color and records direct writes to the sound chip. This recording can be played back from another ROM using a custom player.

The included player is very fast and can easily play songs that would choke LSDj on a Game Boy Classic. Since recordings take a lot of ROM, an MBC5 cartridge is recommended.

ROM+CPU consumption varies with song contents. Features like sample playback or FAST/DRUM P and V commands are especially demanding, since they update the sound chip 360 times/second.

To reduce CPU consumption and interfere less with game logic and graphics, it can help to batch up player calls. Examples:

  • Full speed (default): Call player six times/frame, evenly spaced out. Allows ~11 kHz sample playback ("1x" sample speed).
  • Half speed: Make two player calls in a row, three times/frame. Allows ~6 kHz sample playback ("0.5x" sample speed).
  • Normal speed: Make six player calls in a row, once a frame from VBL interrupt. Useful if sample playback is not needed.

lsdpack's People

Contributors

cyberic99 avatar jkotlinski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

lsdpack's Issues

Idea: LZ77 compress command bytes

If further compression is needed, it would be a good win to LZ77 compress the command bytes only, as there is a lot of repetition there.
Command argument bytes should be excluded from this compression though, as they vary too much.

To keep CPU usage low, it would be best not to have such compression enabled by default.

Nothing written to .s file

I cannot get anything written to the .s file. Either I get the following:

./lsdpack lsdj.gb
Recording to 'lsdj.s'
Loading lsdj.gb...
Song 1...
wrote 128 sample bytes, 73399 music bytes
Song 2...
wrote 0 sample bytes, 73457 music bytes
Song 3...
wrote 0 sample bytes, 73391 music bytes
Song 4...
wrote 0 sample bytes, 73352 music bytes
Song 5...
wrote 0 sample bytes, 73321 music bytes
Song 6...
wrote 0 sample bytes, 73363 music bytes
Song 7...
wrote 0 sample bytes, 73430 music bytes
Song 8...
Song 9...
Song 10...
Song 11...

...etc etc. Or it just hangs on the first part:

./lsdpack lsdj.gb
Recording to 'lsdj.s'
Loading lsdj.gb...
Song 1...

This happens depending on the sav file I'm using, but neither results in a non-empty .s file. I built the lsdpack with cmake on Mac and have a lsdj.gb and lsdj.sav in the same folder.

.gbs file is stuck

Hello again.

When recording the test song from the save file below, the resulting .gbs stops playing and stays 'stuck' after 10s

lsdj.sav.zip

Compression

Compress the music stream (LZ77? Huffman?)

Huffman saves ~150 kbyte on Tachyon Beam

feature request: raw register dump

It could be interesting to get a raw register dump of a song in text form, a bit like what vgm2txt does:

<cycle> <address> <value>
or
<address> <value>
<wait x cycles>
...

This could be useful, in order to analyze some songs

An option to choose if we want the 'optimized' (without redundant reg writes) or the raw dump could be useful too.

wave channel seems to pitch shift down after conversion

lsdj.sav.zip (v8.5.1)
lsdj-7_0_2.sav.zip (v7.0.2)

Following steps from the README:

$ lsdpack -g lsdj-7_0_2.gb
.gbs mode enabled
Loaded lsdj-7_0_2.gb
Playing song 1...
Recording to 'lsdj-7_0_2-1.s'
Wrote 16 samples
Song 1: 266 bytes
OK
$ rgbasm -o lsdj-7_0_2-1.o lsdj-7_0_2-1.s
$ rgblink -o player-1.gb boot.o player.o lsdj-7_0_2-1.o
$ rgbfix -v -m 0x19 -p 0xff player-1.gb
$

Running the result in emulator results in something very pitch-shifted down.

Tested with:

  • Big Sur
  • rgbds v0.5.1
  • lsdj v8.5.1 (lsdj.sav.zip) and lsdj v7.0.2 (lsdf-7_0_2.sav.zip)
  • OpenEmu's gameboy emulator which seems to be Gambatte

I can post MP3s of what I'm expecting vs what I'm hearing if needed.

Commenting out the body of the transform function in https://github.com/jkotlinski/lsdpack/blob/master/rules/rule_pitch.cpp seems to handle this issue.

support older LSDJ version and littlefm

Hi

I'm trying to convert some songs made with LSDJ 4.7.2 to .gbs, with no success.

My .gb file is 2.0MB in size, and is patched with littlefm.

I first opened the .gb file with gambatte, to create a .sav file, then launched lsdpack.

It generated 32 .s files, that were all 6 lines long.

So I downloaded lsdj-4.7.3, renamed my .sav to match the .gb filename, and launched lsspack again.

but I still got the same result.

So I'm wondering if older lsdj versions are supported (I hope so), and also if I missed some steps.

Also, is the H FF step still necessary, and does lsdpack use the .sav file or just the .gb ?

thanks for your answers!

on the structure of lsdj.s

This is not an actual issue, more of a request of documentation.
I would like to try to port the lsdj player to GBA.
AFAIK, GBA has the same audio registers of GB/GBC plus some additional ones.

From my understanding, lsdpack translated lsdj music into cpu registers read from an emulator, those values are saved and the player on a ROM proceeds to play back the values copying them to the register.
It should be possible to play back the registers on GBA rewriting a routine for ARM (maybe even C could be suitable, if it's not too slow?), maybe even adding the compression, but I'm trying to figure out the starting register address, the order and the correspondance of the register values written in the "lsdj.s" file.

If there could be some kind of documentation on the structure of the lsdj.s file, or how many and which the addresses are I would be glad since I can't figure them out neither from the player routines (I'm not familiar with assembly, at least for now), nor from the writer.cpp file (I clearly see where it writes, I just don't understand from which addresses).

Optimize software envelopes

Little Sound Dj 8.8.0+ uses software envelopes, significantly increasing the number of registry writes.
This should probably be optimized to reduce the CPU+ROM penalty.

'k' cmd kills all subsequent notes in wave channel

lsdj.sav.zip (v8.5.1)

Running conversion on the linked save file:

$ lsdpack -g lsdj.gb
.gbs mode enabled
Loaded lsdj.gb
Playing song 1...
Recording to 'lsdj-1.s'
Wrote 16 samples
Song 1: 331 bytes
OK
$ rgbasm -o lsdj-1.o lsdj-1.s
$ rgblink -o player-1.gb boot.o player.o lsdj-1.o
$ rgbfix -v -m 0x19 -p 0xff player-1.gb
$

A k00 cmd is after each note in all three types of channels. Only the first note of the wave channel is played in a given bar.

This issue assumes the body of the transform function in https://github.com/jkotlinski/lsdpack/blob/master/rules/rule_pitch.cpp is commented out which is related to #23

I have observed that sometimes changing the instrument in the wave channel seems to reset this, meaning the first note with the new instrument will be played until another k cmd is encountered. I don't know exactly how to repro this though, but I can dig more if it would be useful.

Tested on:

  • Big Sur
  • rgbds v0.5.1
  • lsdj v8.5.1 (lsdj.sav.zip) and lsdj v7.0.2 (lsdf-7_0_2.sav.zip)
  • OpenEmu's gameboy emulator which seems to be Gambatte

I get around this by using e00 instead if I want to cut a note presently.

player.o

i cant seem to find player.o anywhere in the exe or the source. is there anywhere i can get it?

generated .gbs files sound incorrect

Hi,

I tried to generate .gbs files from some of our songs.

Some of them sound more or less different than the song played in lsdj.

For instance, here is a .sav file with a short intro on noise channel.

noise_opt.zip

If I comment all rules in writer.cpp::optimize_music_stream(), the .gbs sounds right (noise_ok.gbs)

but with optimizations, it sound incorrect (noise_nok.gbs).

Both .gbs files and the .sav are in the zip.

I tested it with lsdj 4.7.3

Thank you!

recording wav loop speed issue

Hello Johan!
Today I have found an issue after recording tracks. If you have wav channel with loop speed 1 than it sounds not right ( note C sounds like D) and some distortion also. I'm using 8.4.4 lsdj.

stops at empty slot in savefile

lsdj17.zip

i tried searched scene.org file archive for lsdsng and found some tunes from Syntax'17 party
dunno what lsdj version they used...

I added some lsdsngs to an empty sav and found out something was wrong with 2 of the songs
so i ended up deleting them in lsdj.. with 2 left and HFF'ed I said "lsdpack jomp pan it" and it couldnt manage
to skip empty areas in the sav and process all songs

segfault when dumping

Hello

I tried to make a raw registers dump of a test song, I get a segfault

The provided .sav file has only one song
I am using lsdj-4.7.3

command:

lsdpack -r -d lsdj.gb

I get a crash, here is the backtrace from gdb:

#0  0x00007ffff7aa149c in ?? () from /usr/lib/libc.so.6
#1  0x00007ffff7a51958 in raise () from /usr/lib/libc.so.6
#2  0x00007ffff7a3b53d in abort () from /usr/lib/libc.so.6
#3  0x00007ffff7a9563e in ?? () from /usr/lib/libc.so.6
#4  0x00007ffff7aab22c in ?? () from /usr/lib/libc.so.6
#5  0x00007ffff7aad07c in ?? () from /usr/lib/libc.so.6
#6  0x00007ffff7aaf9f3 in free () from /usr/lib/libc.so.6
#7  0x00007ffff7a99ae6 in _IO_default_finish () from /usr/lib/libc.so.6
#8  0x00007ffff7a8b905 in fclose () from /usr/lib/libc.so.6
#9  0x0000555555582a2e in DumpWriter::record_song_stop() ()
#10 0x0000555555581a6d in on_ff_write(char, char, unsigned long) ()
#11 0x00005555555a3f9c in gambatte::Memory::nontrivial_ff_write(unsigned int, unsigned int, unsigned long) ()
#12 0x000055555559b86c in gambatte::Memory::ff_write(unsigned int, unsigned int, unsigned long) ()
#13 0x000055555559a4fe in gambatte::CPU::process(unsigned long) ()
#14 0x000055555558f001 in gambatte::CPU::runFor(unsigned long) ()
#15 0x000055555559c5ac in gambatte::GB::runFor(unsigned int*, long, unsigned int*, unsigned long&) ()
#16 0x00005555555816b2 in run_one_frame() ()
#17 0x00005555555816e6 in wait(float) ()
#18 0x00005555555819b5 in play_song() ()
#19 0x0000555555582474 in record_dump(int, char**, bool) ()
#20 0x00005555555826af in main ()

what is surprising is that the .sav file should only contain one song. or is it corrupted somehow ?

And when using the -g option, I get:

lsdpack -g lsdj.gb
.gbs mode enabled
Loaded lsdj.gb
Playing song 1...
Recording to 'lsdj-1.s'
Wrote 16 samples
Song 1: 3311 bytes
Playing song 2...
Recording to 'lsdj-2.s'
Wrote 16 samples
Song 1: 3318 bytes
Playing song 3...
Recording to 'lsdj-3.s'
Wrote 16 samples
Song 1: 3313 bytes
Playing song 4...
Recording to 'lsdj-4.s'
Wrote 16 samples
Song 1: 3313 bytes
Playing song 5...
Recording to 'lsdj-5.s'
Wrote 0 samples
Playing song 6...
Recording to 'lsdj-6.s'
Wrote 0 samples
Playing song 7...
Recording to 'lsdj-7.s'
Wrote 0 samples
Playing song 8...
Recording to 'lsdj-8.s'
Wrote 0 samples
Playing song 9...
Recording to 'lsdj-9.s'
Wrote 0 samples
Playing song 10...
Recording to 'lsdj-10.s'
Wrote 0 samples
Playing song 11...
Recording to 'lsdj-11.s'
Wrote 0 samples
Playing song 12...
Recording to 'lsdj-12.s'
Wrote 0 samples
Playing song 13...
Recording to 'lsdj-13.s'
Wrote 0 samples
Playing song 14...
Recording to 'lsdj-14.s'
Wrote 0 samples
Playing song 15...
Recording to 'lsdj-15.s'
Wrote 0 samples
Playing song 16...
Recording to 'lsdj-16.s'
Wrote 0 samples
Playing song 17...
Recording to 'lsdj-17.s'
Wrote 0 samples
Playing song 18...
Recording to 'lsdj-18.s'
Wrote 0 samples
Playing song 19...
Recording to 'lsdj-19.s'
Wrote 0 samples
Playing song 20...
Recording to 'lsdj-20.s'
Wrote 0 samples
Playing song 21...
Recording to 'lsdj-21.s'
Wrote 0 samples
Playing song 22...
Recording to 'lsdj-22.s'
Wrote 0 samples
Playing song 23...
Recording to 'lsdj-23.s'
Wrote 0 samples
Playing song 24...
Recording to 'lsdj-24.s'
Wrote 0 samples
Playing song 25...
Recording to 'lsdj-25.s'
Wrote 0 samples
Playing song 26...
Recording to 'lsdj-26.s'
Wrote 0 samples
Playing song 27...
Recording to 'lsdj-27.s'
Wrote 0 samples
Playing song 28...
Recording to 'lsdj-28.s'
Wrote 0 samples
Playing song 29...
Recording to 'lsdj-29.s'
Wrote 0 samples
Playing song 30...
Recording to 'lsdj-30.s'
Wrote 0 samples
Playing song 31...
Recording to 'lsdj-31.s'
Wrote 0 samples
Playing song 32...
Recording to 'lsdj-32.s'
Wrote 0 samples
OK

PS: previously I already successfully converted some songs using the same LSDJ version, so at some point, it was working (maybe with an older version of lsdpack)

I'm attaching lsdj.gb and lsdj.sav below.

lsdj.zip

Thank you !

rgbasm fails for player.s and boot.s for rgbds v0.5.1

$ rgbasm -o player.o ../lsdpack/player.s
ERROR: ../lsdpack/player.s(421):
    syntax error, unexpected newline
ERROR: ../lsdpack/player.s(423):
    syntax error, unexpected newline
ERROR: ../lsdpack/player.s(425):
    syntax error, unexpected newline
ERROR: ../lsdpack/player.s(427):
    syntax error, unexpected newline
ERROR: ../lsdpack/player.s(429):
    syntax error, unexpected newline
ERROR: ../lsdpack/player.s(431):
    syntax error, unexpected newline
ERROR: ../lsdpack/player.s(433):
    syntax error, unexpected newline
ERROR: ../lsdpack/player.s(435):
    syntax error, unexpected newline
$ rgbasm -o boot.o ../lsdpack/boot.s
ERROR: ../lsdpack/boot.s(51):
    syntax error, unexpected newline
ERROR: ../lsdpack/boot.s(53):
    Local label '.wait_button_pressed' in main scope
FATAL: ../lsdpack/boot.s(57):
    Local label reference '.wait_button_pressed' in main scope

Tested on Big Sur and Windows 10. Can be fixed by adding colons to the end of each line indicated in player.s and lines 51 and 91 in boot.s.

cmake build problem on Debian

I am using an up to date Debian 10 with cmake 3.13.4-1 and when I do a cmake . I get the following error:

-- The C compiler identification is GNU 8.3.0
-- The CXX compiler identification is GNU 8.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
CMake Error at CMakeLists.txt:72 (install):
  install TARGETS given no RUNTIME DESTINATION for executable target
  "lsdpack".


-- Configuring incomplete, errors occurred!
See also "/home/user/code/gbdev/clockboy/lsdpack/CMakeFiles/CMakeOutput.log".

The log file is not very helpful, I'm including it just in case. CMakeOutput.log

The behaviour is the same if I specify an output directory.

I fixed this problem with the following patch:

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 0081489..1efb078 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,7 +69,8 @@ add_executable(makegbs makegbs.cpp getopt.cpp)
 
 get_directory_property(TARGET_NAMES BUILDSYSTEM_TARGETS)
 
-install(TARGETS ${TARGET_NAMES})
+install(TARGETS ${TARGET_NAMES}
+	DESTINATION .)
 
 foreach(TARGET_NAME ${TARGET_NAMES})
     set_property(TARGET ${TARGET_NAME} PROPERTY CXX_STANDARD 14)

This fixes the problem on my Debian, but I didn't test it on Windows or with earlier cmake versions.

Aborted because song is longer than 1 hour despite HFF command being in place

Hi! I'm having a small issue, and I don't know if it's user error or what, but it's odd. I've put an HFF command in and tested it within LSDj to no avail to get past this error. I've tried both Windows and Linux, both do it. I'm using LSDj 4.3.8.

Here's a video showing some of the song and the HFF command:
https://github.com/jkotlinski/lsdpack/assets/69173292/26dfd9bb-9f98-41e9-b47b-8180f8b0667d

Pic of the error:
image

Here's my sav file, incase it's needed:
lsdj.zip

Any help is greatly appreciated!!

Best compatible LSDJ version and known quirks

First of all: Thank you for this tool! Very sad to discover this so late. This would've been great to enter demoscene competitions with LSDJ tracks.

I was wondering what the best version would be to use with lsdpack. 8.5.1 was the latest stable version around the time this repo had its last release. Would that be the advised version?

I also noticed that some pitch shifts in 5.x.x versions were handled a little differently by lsdpack. What are some of the things to keep in mind when wanting create a optimized track?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.