kshootmania / ksm-chart-format

Music game chart format (.ksh/.kson) specifications for K-Shoot MANIA
Creative Commons Zero v1.0 Universal
8 stars 0 forks source link

Better chart formats? (feedback is welcome!) #1

Closed m4saka closed 4 years ago

m4saka commented 5 years ago

Edit: Latest kson spec link: https://github.com/m4saka/ksh2kson/blob/master/kson_format.md


I know KSH format is not so great. It's basically designed referring to the jubeat_analyser format and StepMania (.sm) format. (The parameters m=, o=, t= and bar lines (--) are from the jubeat_analyser format.)

KSH format problems:

KSH Chart Format Specification: ksh_format_spec.md

Any feedback would be appreciated!

nashiora commented 5 years ago

Does this mean an entirely new format is up for consideration? Or would "upgrades" to KSH still be preferable?

If something entirely new is desired, I've always thought a binary format to be great. Human readable is great, but if the editor is fully-featured there's little use for it other than "debugging" of sorts.

If a human-readable form is still desired, being more explicit with chart information and separating the lanes would do wonders still.

My attempt at a binary format kept each lane of the chart in a separate array with positional + length data attached. A position could either be a fractional value, Measure + fraction of a measure, or just a double representing the same thing. I've had a terrible time using fractions in my code and fell back to floating point for both implementation and storage because of it, but fractional positions more closely reflect the current KSH format (since each line is a single 1/n of each measure.) Length being 0 for chips and the same data type as the positional data for length makes sense, or a flag telling if the object is a chip or not is something I've also done for space saving on disk.

Information like spins and fx parameters are probably best attached to the objects themselves, but I've also had a separate Events "Lane" (or multiple event lanes, one for each important kind) which changes global state instead of being a single-use parameter. The events lanes are good for camera controls, for example, so doing it for most other things wasn't a stretch. An Event Land for slam spins would allow those to play anywhere, as well, not just on a slam hit, as another example.

I've always hated working with laser segments in KSH files, but slams have been the most frustrating thing to know if I did correctly. A slam should definitely be an instantaneous self-described object separate from the linear segments. Then there's no ambiguity and no lower-bound on laser segment length (like the 1/32nd division is.)

I'd LOVE to see as many things parameterized as possible, which would mean updating the behaviour as well though. For example, an amplitude parameter for the half spin slam effect instead of it always being a constant amount, or a "shape" and associated parameters for laser segments, allowing curves without tons of linear segments (and even maybe parameterizing the "smoothness" so people who like the low-segment curve look can tune that as well?) This all might be out of scope of the format, but is worth considering and discussing, I think, for future implementations to avoid more backwards-compat hacks.

I'm a bit dazed and can't think of other important things, and this isn't even a good write up in the first place I don't think, but that's a lot of my thoughts on KSH and my experiences using it and trying to replace it for my projects.

nashiora commented 5 years ago

I'd still like to finish up my own binary format and have an implementation in C/++ soon, if that's something you're interested in maybe that can be done with your help? A more "official" implementation that could be used?

I love this stuff anyway, if you have stronger ideas for other things I'd still love to help whatever direction you take it.

albshin commented 5 years ago

Just my simple input into this, but what are your thoughts on implementing something similar to BMSon? https://bmson-spec.readthedocs.io/en/master/

In regards to beatmaps breaking between versions, I think that's just something that needs to be handled by the program itself similar to versioning an API. (The program would interpret older charts in a "compatibility" mode as to not "convert" the file for hashing purposes).

In regards to internet rankings and hashing, how much slower is hashing the whole file vs just hashing the chart game data?

m4saka commented 5 years ago

@nashiora, Thanks for your advice! Creating an entirely new format is intended. I bet that would be far better than using KSH-based one.

In general, binary formats are not flexible when we need to add unpredictable new features. I didn't dig into your binary format in detail, but does it work even if BT notes also had audio effects in future or the format needed to support song lyrics subtitles? We would need "magic numbers" for each feature in binary formats, but I'd say they are no better than bad namings. We need to worry about duplicate magic numbers if original extensions are implemented in third-party clients. It is clearly true that binary formats can be loaded faster, but I believe the speed would not be so different from text formats in ordinary charts.

I think your design of the format is good. Using note arrays is nice as it will greatly reduce the cost for parsing charts, and I totally agree with your opinion about laser slams. But I don't think curving lasers should be supported in KSM (because it would not be supported in a similar arcade game SDVX).

@albshin, Using JSON is a good idea. Since there are a lot of optimized libraries for parsing JSON, the speed would not be a problem.

The bmson format is well-organized, but there are some different points between KSM and BMS:

It seems that the resolution of a measure is 1/960th instead of 1/192th in the bmson. As there are some charts that have unusual resolutions (e.g. there are 1/10th chip notes in "Azul (remix)"), using higher resolutions than 1/192th or using fractional numbers would be better. For implementation, maybe we need to use fixed resolutions (I've currently planned to use 9600 in KSM), so there will be extra costs for fractions. I think 960 is large enough for resolutions (although 9600 would be better), so using the fixed resolution 960 would be a good choice if we use a bmson-like format.

In regards to beatmaps breaking between versions, I think that's just something that needs to be handled by the program itself similar to versioning an API. (The program would interpret older charts in a "compatibility" mode as to not "convert" the file for hashing purposes).

I didn't mention about hashing problems by using different editor versions, but it would be one solution for that. In order not to make a complicated "compatibility" mode necessary, we need a good format!

In regards to internet rankings and hashing, how much slower is hashing the whole file vs just hashing the chart game data?

Actually eliminating chart lines before hashing in current KSH is not that slow and feasible enough for checking one file. However, although I didn't compare the speed, I believe hashing all ksh files in songs directory considering chart-related lines would be slow and not realistic. (It can be solved by creating an SQLite table relating the original file hashes to hashes used for Internet ranking.)

It is great to specify which items are chart-related and which items are not for both lower cost and better compatibility. For example, in the case of KSH, using "#" before not chart-related lines will work (e.g. "#level=" instead of "level=", and using as is about "t=" and "beat="). With this specifier, we won't have to worry about old versions misrecognize new parameters as chart-related ones. If it is possible to separate chart-related information and header-related or audio-related information, no costs are needed and there would be no upward compatibility problems for hashing charts.

JSON can be ambiguous if it comes with extra whitespaces or unsorted keys. Removing whitespaces and sorting keys will be required before hashing. That's also a problem that JSON has.

Drewol commented 5 years ago

I think a binary format is the way to go because of the almost guaranteed superior speed and size but a well thought out text format is ok as well. I don't think expanding a well designed binary format would be much harder than expanding a text based one.

We need to worry about duplicate magic numbers if original extensions are implemented in third-party clients.

I don't think compatibility with third party modifications to the format should be necessary as they clearly went outside of the spec and thus should not expect others to be compatible with them.

But I don't think curving lasers should be supported in KSM (because it would not be supported in a similar arcade game SDVX).

I think this is a bad mindset. There is no good reason to limit what is possible to do in the format just because it is something that is currently missing in the SDVX arcade game. Especially for curves as they are something that are relatively easy to add and relatively large number of charts use curves and the current way you have to make them is very tedious work for chart makers.

As for note placement resolution I mostly agree with what you say. I think storing fractions should be considered even though the cost of them might be higher than just storing an "index" in the measure, the cost might still be worth it for what we gain. We also have to consider the interaction between a fixed division and the time signature if a fixed division is to be used, maybe you already thought about this but you didn't mention it.

albshin commented 5 years ago

@m4saka Thanks for replying to my comment. I've thought about this a bit more and want to share my thoughts again.

I've created a theoretical bmson like spec in order to address some of the points you made along with an example of extending the spec and converting the first measure of Azul(remix) to pulses. It's not perfect and it's missing some of the original spec but it's a quick rough draft.

https://gist.github.com/albshin/cf535afc3f94f7d7f7c7e3d1d9ff41cf

Now your comments.

Using JSON is a good idea. Since there are a lot of optimized libraries for parsing JSON, the speed would not be a problem.

I agree. This makes it be human readable, performant, easy to extend, and easy to read. A nice tradeoff in my opinion.

There are not so many keysounds, so it would be better if there are different arrays for different lanes.

Notes are now decoupled from SoundChannels in the modified bmson format. I've grouped notes by type but that can be easily split into different lane arrays.

We need actual time signatures instead of bar lines in bmson because KSM has beat-related audio effects (e.g. Retrigger, Gate, Wobble).

In my draft, FXes are tied to a pulse as they are mapped to FXButtons and Laser points. This let's them be tied to a beat.

It seems that the resolution of a measure is 1/960th instead of 1/192th in the bmson. As there are some charts that have unusual resolutions (e.g. there are 1/10th chip notes in "Azul (remix)"), using higher resolutions than 1/192th or using fractional numbers would be better.

So I actually took a harder look into bmson. bmson isn't actually 1/960th. It just means that it supports 960 pulses in a measure (assuming a measure is in 4/4). If a song had a 6/8 time signature, since a quarter note = 240 pulses, an eighth note = 120 pulses making the measure 720 pulses. (6*120 = 720). If we wanted to map a note to the 1/10th beat of the measure, the note would be on pulse 72 ((1/10)720), 3/10 would be 216 ((3/10)720), etc.

You can increase the granularity by increasing the resolution size of a quarter note (by default it is 240).

I've currently planned to use 1/9600 in KSM

Does this make sense realistically? Can songs be written to have notes on the 1/9600th note of a measure? Maybe I'm misunderstanding here.

Actually eliminating chart lines before hashing in current KSH is not that slow and feasible enough for checking one file. However, although I didn't compare the speed, I believe hashing all ksh files in songs directory considering chart-related lines would be slow and not realistic

After thinking about online rankings and hashing, is it something the new file spec should really consider? I think it's something out of scope for a file spec and is something best left to be implemented by whoever wants to create an online ranking system. Ideally a central database for beatmaps is created and then ranked beatmaps get frozen from changes (like osu and Beat Saber) but I don't think it's relevant to the file spec.

Regarding Drewol's comments

I think a binary format is the way to go because of the almost guaranteed superior speed and size

I agree that binary would be better in terms of performance and size but it's a lot more tedious to parse vs something like JSON. Every language has efficient parsers for JSON already. In regards to size, is it really a big issue regarding beatmaps? From my experience, a large bulk of a beatmap's size comes from the FX preview songs per difficulty rather than the chart files themselves. In my opinion, that's something that should be addressed before optimizing chart file sizes.

I think this is a bad mindset. There is no good reason to limit what is possible to do in the format just because it is something that is currently missing in the SDVX arcade game.

Agreed. There's no reason for KSH to limit itself to what the arcade can do. If you want KSH to be a faithful arcade emulation, then I understand but in my opinion, KSH should try to give an unique experience that can't be found in the arcade version (or EAC). It'll also give charters a better experience if curves were supported.

Drewol commented 5 years ago

As for the curve implementation I have had in mind, it'd work like this https://www.desmos.com/calculator/dmkkhu0six but you could probably also have two curve points instead of just one but I haven't figured out the math for that yet. This implementation fills a few criteria that I want such as:

nashiora commented 5 years ago

@m4saka As far as future expandability concerns, I've implemented a lot of the properties of objects as bit-flagged optional. Even with only 8bit flags, you have a lot of expansion room since not very many new features are likely to be added (and even then, the final flag can be specified as an extension flag instead allowing for theoretically infinite flagging of note features.) For example, something similar to how I've done in the past:

Basically, all required data is in pre-determined placed and flags more-or-less add data linearly to the end of the object. This means that, assuming no breaking format changes, updates to the way things work need only give meaning to a new flag, and since flags are intended to be processed in-order there should be no breaking issues when reading old versions where the flags are off anyway. This WILL cause issues when reading newer features on older versions, as the old version won't know how much data to skip if a flag is on. A more spacious format could account for this by instead of using flags, using a single byte ID + length of payload data, so implementations can skip ID's they don't recognize.

I'm still partial to the bitflags for compactness, but having [ OBJ_ID :: OBJ_PROPERTY_COUNT :: OBJ_POSITION :: < ARRAY OF OBJ_PROPERTY > ] is a solid option for a safer format if that's desired.

As far as Laser Curves, SDVX may not support them but that doesn't mean that the concept isn't already in use. Everyone uses small linear segments for that purpose, and a single laser curve need only act as a linear one gameplay wise but provide the same look, and be MUCH easier to edit when charting. You wouldn't have to delete all your segments and try again to slightly change the shape. Not a necessary feature, but when I implemented it I loved how it looked. I can't find video or a stream of me working with it, so I can't really show it off :/ It supported a few different curve options, though, for some great freedom in how they looked.

albshin commented 5 years ago

I have a minor suggestion that wouldn't require a whole new file format.

I would love to have a "romanised title" and a "romanised artist" field in the header similarly to osu. This would help players that don't have a Japanese keyboard installed on their OS to be able to search for songs with Japanese characters. You can currently implement searching by romanised title by storing the path to the beatmap within a database (assuming the folder containing the beatmap is named correctly). However this is prone to break very easily just by changing the folder name that the beatmap is contained in.

nashiora commented 5 years ago

I second the additional artist/title (and add that maybe everything text based should have the optional romanized counterpart.) for the same reasons, it wouldn't be hard and is super useful. It's not like we can force them to represent the same thing, but it's a really good step in the right direction for searchability and ease of use for non-Japanese users.

m4saka commented 5 years ago

But I don't think curving lasers should be supported in KSM (because it would not be supported in a similar arcade game SDVX).

I think this is a bad mindset. There is no good reason to limit what is possible to do in the format just because it is something that is currently missing in the SDVX arcade game.

I agree. This makes it be human readable, performant, easy to extend, and easy to read. A nice tradeoff in my opinion.

As far as Laser Curves, SDVX may not support them but that doesn't mean that the concept isn't already in use. Everyone uses small linear segments for that purpose, and a single laser curve need only act as a linear one gameplay wise but provide the same look, and be MUCH easier to edit when charting.

OK, I understood. Actually I came up with the problem of direction change caused by non-linear lasers, but it would not be a problem according to @Drewol, thanks.

I've currently planned to use 1/9600 in KSM

Does this make sense realistically? Can songs be written to have notes on the 1/9600th note of a measure? Maybe I'm misunderstanding here.

I just meant the number of pulse that stands for 1 measure in 4/4 is 9600.

As far as future expandability concerns, I've implemented a lot of the properties of objects as bit-flagged optional. Even with only 8bit flags, you have a lot of expansion room since not very many new features are likely to be added (and even then, the final flag can be specified as an extension flag instead allowing for theoretically infinite flagging of note features.)

I admit future expandability can be maintained even if we choose a binary format, and it would not need any extra bytes (e.g. the same keys like "x" "y" "l" for every note). But I still prefer @albshin's JSON approach. As a developer, implementing the whole spec for just using a specific information is tiresome. With a JSON-based format, since it is friendly to modern languages, you can get or edit specific parts in charts by just using your favorite language and its JSON parser.

I would like to work on a revised spec based on the first draft by @albshin.

I would love to have a "romanised title" and a "romanised artist" field in the header similarly to osu.

I second the additional artist/title (and add that maybe everything text based should have the optional romanized counterpart.)

We definitely need either. In addition, we may need "movie author" and "genre" (like BMS) field as far as I've heard from users. They're currently written in the optional "information" field.

Drewol commented 5 years ago

Ok, so do we have most of the problems of ksh solved now? I just wan't to make sure before moving on.

It seems to me like the only things left is the UTF-8/ASCII problem which could be solved by just writing in the spec that it's UTF-8 and anyone using something different will not be complying with the spec so it won't oficially be supported, and the hashing thing which is a harder problem but as @albshin says it might be best to leave that up to each IR system creator.

I'm pretty happy with JSON though I would've liked to see a binary format but I realized the other day that many higher-level languages do not have very good binary readers so for applications like for example my own ksh2svg it might be very hard to read the new format if it were to be binary.

nashiora commented 5 years ago

Yeah, binary being hard for some platforms is a good reason.

m4saka commented 5 years ago

I forgot to share my plans about scoring. I mentioned hashing using the word "Internet ranking" (IR), but I would also like to use it for managing local scores.

The way for score management which the current KSM uses is badly implemented. Each scores is tied to a relative path of the chart. Due to this, the current KSM will never work with multiple song directories. If hashing is not costly and feasible enough to check all the files in registered directory, we can use the hash as a key of scores or play histories. I think it's meaningful.

I also agree that this requirement is not necessarily fulfilled in the chart spec, but if it can be solved, it would be better.

m4saka commented 5 years ago

In this point, we should avoid floating-point values if possible (e.g. for laser x-axis position). If just opening and saving does not affect the hash is better.

But this design is not necessarily the must.

nashiora commented 5 years ago

I always prefer a fixed width range for things like that if possible, yes.

m4saka commented 5 years ago

OK, now I'm preparing a revised chart format spec based on the kshon spec.

m4saka commented 5 years ago

I've finished a revised spec! https://gist.github.com/m4saka/a89594a17dc9422d75e01998bcfd2722/7a421bc54d3b81b4e01601e8ade715df6437ebb9

Major changes:

Drewol commented 5 years ago

Looking good so far đź‘Ť

I have some suggestions:

dictionary NoteInfo { BTNote[][]? bt; // bt notes (first key: lane index) FXNote[][]? fx; // fx notes (first key: lane index) LaserSection[][]? laser; // laser notes (first key: lane index (0: left knob, 1: right knob)) }



And also there seemed to be some redundancy for which lane the lasers and fx are in, it's both in the key and on the object. Maybe that is intentional but it looked a little weird to me.
m4saka commented 5 years ago

Maybe adding a color field to DifficultyInfo would be neat.

I was also thinking whether to add the color option to DifficultyInfo, but finally I didn't add it. I think some skin creators want to adjust the difficulty colors in detail, so setting color code (like #FF0000) is not a good choice. But preparing every color name (like HTML color names) is not realistic, and also skin creators will not be able to fully control all these colors. In my opinion, I think assigning colors only to known difficulty names (short_name) by the kson clients is better (but it would be a weird logic).

I was thinking that maybe the lasers could be made into another level of arrays so you also have arrays of laser sections, something like this ...

LaserSection is a great solution! We will not have to check which lasers are connected, and also wide-range lasers can be correctly defined.

And also there seemed to be some redundancy for which lane the lasers and fx are in, it's both in the key and on the object. Maybe that is intentional but it looked a little weird to me.

Sorry, it was not intentional and it's a simple mistake. I'll fix it.

m4saka commented 5 years ago

Updated the spec. https://gist.github.com/m4saka/a89594a17dc9422d75e01998bcfd2722/d1b00ae739f16f21742edcd47265e3d1eba621d9

With laser sections, just having laser points is enough, so I changed the segments to points.

I also changed the camera event type name "distance" to "zoom" referring to @nashiora's Haven (https://github.com/nashiora/Haven). With this, bigger values can clearly mean a closer look.

BTW, I chose two-dimensional arrays for representing lanes & notes, but it is not necessarily good. For example, in NoteInfo, BT-A and BT-B lanes cannot be skipped even in a chart that only have BT-C notes. The same problem will likely occur in AudioEffectEventInfo. I have not fixed this yet, but using dictionaries may be better. If dictionaries are used, do you think their key should be index numbers (like "0", "1", "2", "3") or lane names (like "l", "r" or "a", "b", "c", "d")?

nashiora commented 5 years ago

For clarification, JUST the first point in a slam contains the information about its slams sounds and effects, yes? Also, the documentation in that area still discusses l which is no longer present.

I definitely think the 2d array is a bit much.

m4saka commented 5 years ago

For clarification, JUST the first point in a slam contains the information about its slams sounds and effects, yes? Also, the documentation in that area still discusses l which is no longer present.

Hmmm... That would be confusing, and we should have had a length parameter in lasers. I will switch back to the previous LaserSection & LaserNote specification.

But I realized that we cannot represent the last slam in a laser section with the LaserNote spec. Maybe we need the "end" values of laser's x axis in addition to the "beginning" values, although that will make redundancy. Using LaserPoint, we won't have this problem, but it'll have a problem about confusing position for specifying slam sound. Hmm...

I definitely think the 2d array is a bit much.

Do you mean dividing into lanes is also a bit much? (I ask this question because using dictionary for lanes, which I suggested, is more complex than the 2d array.)

nashiora commented 5 years ago

Is a regular array of objects not an option? I'm not familiar with what we're using for description here, honestly.

But I realized that we cannot represent the last slam in a laser section with the LaserNote spec.

With a single "alpha" position, yes. As you mentioned I've always used two, the begin and end. Using the points is still fine, so long as you mark in the spec that the first point of a slam has the info for it.

I don't think finding a slam in the array is an issue, but if needed an int[] can be added to LaserSegment of indices into the points where slams start. I don't think that's a good or necessary idea, but may as well say it.

m4saka commented 5 years ago

Is a regular array of objects not an option? I'm not familiar with what we're using for description here, honestly.

That would be still an option, but if notes are divided into lanes, it's definitely easier to look at successive notes in the same lane, and it would make enumerating lasers much easier. I admit this technique should not necessarily be applied in the file format, but you will need extra buffers in enumerating laser notes with lane-mixed note arrays.

With a single "alpha" position, yes. As you mentioned I've always used two, the begin and end. Using the points is still fine, so long as you mark in the spec that the first point of a slam has the info for it.

Since every implementation will need to store two values (the begin and end) for a laser note, always using two values is reasonable. But in this case, we need to think about illegal cases (e.g. the end value of the previous laser does not match the next beginning value).

To avoid this, only the last laser in a section can have the "end" value. With this idea, you don't have to worry about illegal cases, and the last slam can be represented.

nashiora commented 5 years ago

I managed to completely misunderstand the data layout in my head, 2d array is totally fine. Don't know what I was thinking honestly.

123jimin commented 5 years ago

Hello, I'm a charter who likes to make gimmicky kshoot charts.

After reading the thread I love how the new spec is being created. I have a few suggestions though:

m4saka commented 5 years ago

@123jimin Thanks for your feedback!

I suggest that the default encoding should be UTF-8 without BOM.

I think so, too. And I think the linefeed code should be LF (not CR+LF).

Default KsonInfo.resolution could be much lower (as low as 12).

I partially understand that, but I think it's good to have high resolution enough by default. I even wonder why KsonInfo.resolution is changeable. If it is set high enough by default (e.g. 240), this value will be rarely specified. I think all charts having the same resolution is good. If there's no charts with a resolution other than 240, kson clients only have to support that resolution, and their implementation would be very simple.

By the way, 12 is too low (32th notes cannot be represented with that value).

DifficultyInfo.name should be optional too. (Leaving index be the only required field.)

If difficulty terms differ depending on kson clients, it would be confusing. So I added this option, and I supposed it is specified by the editor program by default. By this, if a charter uses the KSM editor, the difficulty terminologies will be "LT/CH/EX/IN", and this terms are valid even if players use another kson client.

But allowing it not to be specified is good. DifficultyInfo.name should be optional, but I suppose it will be usually specified by default.

I suggest to implement slams like this (using optional end values) (not considering curves for now)...

I love your suggestion. I think your idea is the best! :+1: As you pointed out, CameraEvent also should use the same one.

I suggest to implement bar lines like this: ...

I also think storing all the bar lines is meaningless, but I don't like your BarLine idea. For unification, the term "l" should be used only for lengths in tick values.

Actually I haven't modified the bmson's bar lines yet, and the current spec of bar lines will not go well with KSM. If it can be modified, I prefer the "real" time signature specification like this. This is more similar to the current KSH format. If the full song is in 4/4 time, specifying time signatures is no longer needed.

dictionary TimeSignature {
  unsigned long index; // Measure No. (not a tick value)
  unsigned long n; // Numerator
  unsigned long d; // Denominator
}

I also prefer this (the same as BMS spec), but it doesn't work well in some indivisible cases (but it is a rare case).

dictionary TimeSignature {
  unsigned long index; // Measure No. (not a tick value)
  double beat; // Numerator/Denominator (e.g. 4/4 = 1.0, 3/4 = 0.75)
}

And I agree with all your other suggestions that I didn't mention.

m4saka commented 5 years ago

New spec! https://gist.github.com/m4saka/a89594a17dc9422d75e01998bcfd2722/7b977963187a9af72d63f40adf3c243799ef7515

Changes:

m4saka commented 5 years ago

Although fixed laser values and camera event values are preferred in hashing, I become to think using double for these values is more "natural" way if curves are supported.

By the way, I think the lane spin & swing can be defined as something like a "macro" for camera values. If these "macros" affect camera values by relative changes, they work in the same way as the current spin/swing behavior. Furthermore, camera values (including the current zoom_top/zoom_bottom) can be tweaked by a laser slam as a trigger. I think allowing notes other than laser slams as a trigger would be interesting.

When the lane spin is defined as a macro, the lane tilt will be implemented as a camera value. Since the lane tilt follows lasers, some translation between lasers and camera values will be needed, and some scaling value is required for this translation (to support "zero"/"normal"/"bigger"/"biggest"). And if tilt value is specified by charter, the translation scale should be set to "zero" automatically. Does anybody have a good idea about this?

m4saka commented 5 years ago

Using a "section" (like LaserSection) for camera events is one solution to set the tilt scale to "zero" automatically while a charter specifying the lane tilt values manually.

nashiora commented 5 years ago

@123jimin's proposed laser idea is probably the best, though part of me still dislikes the space requirement but hey that's not important.

I don't quite know if we're talking about storing the literal position of a bar line; if we are, I hate that idea and agree that they don't need to be stored at all, anywhere. @m4saka's last TimeSignature example is all that's needed for anything bar related, and bars are easily determined by N * resolution.

If that's not what was being talked about, then I have no idea :)

nashiora commented 5 years ago

I really want to spins etc. as things that can be programmed and applied to more than slams. In my implementations, I tended to refer to them as Impulse events. I think it might be fair to restrict these specifically to playable objects, I've made the point of saying "anywhere might be awesome!" but then the common case of slam + spin is now tough to detect, so not a great idea.

Effecting any camera value sounds amazing, I actually implemented something similar in my first SDVX clone where a slam would always move the critical position slightly so the whole lane bobbed back and forth. (https://www.youtube.com/watch?v=tXCeHWFe1Kk is a good example, and the video uploaded right after as well for a more laser heavy section and the effect toned down a bit). Making that (basically for my effect, a slight zoom out and translation in the direction of the slam) an easy-to-apply macro would be fantastic to see, and if designed right it'd be super simple. I can work on some rough spec if needed.

On that note, since my previous example is applied to every slam, (this is probably a bad idea and I'm great at taking things too far) what if your default slam effect could be configured to be one of those macros instead? So no slam effect defaults to a pre-defined macro, and only one (or none) can be specified? Then a whole chart could have a unique feel by just adjusting the default behaviour of slams without going thru the trouble of changing every single one. Maybe a slower more flow-y song would like to add a small swing or bounce to every slam to create a consistent feeling of fluff or idunno words.

123jimin commented 5 years ago

Thanks, I like the current format spec! (Except ow events are represented, but I still have no good idea.) Also, I prefer using TimeSignature instead of BarLine too.

Talking about macros, I made this macro language to create camera effects on my latest chart, which is full of gimmick camera movements. This works by defining macros which add relative camera movements 'on top of' existing camera effects. (Absolute camera movements invoke some problems on recursice macros...)

While I don't think that adding this to the spec is a good idea (performance and security related issues), I think that some portion of this could be helpful.

nashiora commented 5 years ago

Important question: Should a laser section contain its own y value instead and each point inside becomes relative to that, or should those points always be absolute?

so should it be

or

ninjaedit: I prefer the first option personally

m4saka commented 5 years ago

As for camera macros, it may be better to discuss further after the first spec draft. For future expandability, "spin", "half_spin" and "swing" can be used as implicitly-defined macros, then the macro feature itself can be settled in future. The preset spins/swings can be overwritten by a macro with the same name. This will fit @nashiora’s suggestion. I think @123jimin’s script is too much for the spec, but it would be a good reference for macro plans.

Important question: Should a laser section contain its own y value instead and each point inside becomes relative to that, or should those points always be absolute?

I like either, but we should use another term for the y value if it is a relative value.

{ "y":32, [ { "ry":0, "v":-100 }, { "ry":32, "v":0 }, { "ry":64, "v":100 } ] }

m4saka commented 5 years ago

https://gist.github.com/m4saka/a89594a17dc9422d75e01998bcfd2722/586fc30c992d57c3c00dbeff55f61d68cbac0d6e

Changes:

Any feedback is welcome!

m4saka commented 5 years ago

Also we need further information about curves to make progress.

Drewol commented 5 years ago

if the function I linked before then curves simply just need two numbers that are either 0-1 floating or some fixed range like 0-256 and if the two parameters are equal or if either of them are undefined then the laser is straight, but I'm unsure of where these should be placed since the format will use laser points and not segments. The chunithm simulator seaurchin seems to also have some form of curves implemented https://seaurchin.kb10uy.org/wiki/score/curve so maybe we could look at that for inspiration.

m4saka commented 5 years ago

Using bezier (like seaurchin) is still an option but laser direction can be changed midway through a laser note. But maybe we need to predetermine the laser x value for these bezier before playing, and we would simply divide a laser note into n-ths (e.g. 10ths) and calculate these x values. Then direction change may not be a problem. (Actually seaurchin preprocesses these bezier by dividing into points at certain intervals.)

I also found cubic-bezier in CSS3. I believe this one is the two-point version that @Drewol pointed out before. If this is used, the direction is not a problem if the values are restricted between 0 and 1. http://cubic-bezier.com

I haven't figured out how to implement these control points in the current laser/camera point spec, too.

nashiora commented 5 years ago

I still think leaving segment-specific data on the point which begins that segment is the best idea for this. I'm on the boat of storing the two points of the curve equation and always using that to check if it's linear. The easy, default, case is that they're both 0 anyways.

Does a linear and a curve, I assume 0-100 but these are arbitrary values anyway PT_A {(A-B, Line) ry:0, v:-100, a:0, b:0 }, PT_B {(B-C, Curve) ry:192, v:100, a:20, b:80 }, PT_C { (END, Slam) ry:284, v:-100, vf:100, a:0, b:0 }

Yeh?

m4saka commented 5 years ago

That's good. And I figured out that a cubic bezier curve can be approximated by two quadratic curves (quadratic one is the same as the nashiora's example). The quadratic curve is a reasonable choice if you don't mind the number of control points for complex curves.

m4saka commented 5 years ago

https://gist.github.com/m4saka/a89594a17dc9422d75e01998bcfd2722/d539108eed32ea9fe7e93794448c02b15c28548c Added curves to the spec! Currently the value of 0-100 [%] is used for a & b values.

m4saka commented 5 years ago

Here's the TODO list:

// TODO List
//   - lane swing (with a camera macro with curves?)
//   - meta data (which options are to be inherited from KSH?)
//   - BGA layer?

Since "layer" option of the KSH spec allows changing the animation speed and whether to spin or tilt, it is good to consider BGA layers at this time.

Drewol commented 5 years ago

for BGA, are you also considering things like supporting character artwork moving around like on "boss" songs in the sdvx arcade game?

m4saka commented 5 years ago

for BGA, are you also considering things like supporting character artwork moving around like on "boss" songs in the sdvx arcade game?

Not necessarily, but it’s great if it is possible. I think these "boss" BGA layer options can be designed as an extension for the current animation layer. If it is hard work to maintain the positional relationship for these layers for the client developers, it would be okay to implement them as client-dependent features.

m4saka commented 5 years ago

oops

123jimin commented 5 years ago

My thought on camera macros: implement them as relative "patches" to base camera angle/location, where its length is provided when the macro is invoked.

Therefore, each macro invocaton must provide {int tick, uint length, string macro}, where some of the values can be omitted in the file format, and default length may be provided by the macro definition.

The macro definition itself is then simply given by {string name, uint defaultLength, CameraEventInfo body}. I think that this is not the best way, but this would be the most convenient way.

Implementation example:

123jimin commented 5 years ago

Some random ideas (I'm on a phone now so will skip details for now; they all have pros and cons):

m4saka commented 5 years ago

My thought on camera macros: implement them as relative "patches" to base camera angle/location, where its length is provided when the macro is invoked. Therefore, each macro invocaton must provide {int tick, uint length, string macro}, where some of the values can be omitted in the file format, and default length may be provided by the macro definition. The macro definition itself is then simply given by {string name, uint defaultLength, CameraEventInfo body}. I think that this is not the best way, but this would be the most convenient way.

That's what I was thinking. (The word "macro" that I chose may not be good for it.)

I realized I forgot to write them in the KSH spec document, but the lane swing of KSH have three parameters, (1) the scale of the sine wave, (2) how many times to repeat the sine wave, and (3) whether to damp the wave and its type (linear damping or square damping).

If the lane swing is to be implemented as a macro, we need to consider these parameters. Also, apart from swings, you may want to change how many times to spin or how many degrees a half-spin is.

I even think this is too much, but this example can satisfy these requirements (variable names are random):

As for three-time swing with linear decay, you can use {tick:0, macros:[ {"name":"swing", "length":960, "scale":100}, {"name":"swing", "length":960, "scale":-67}, {"name":"swing", "length":960, "scale":33} ]}.

If you want to insert a three-time spin, you can just use {tick:0, macros:[ {"name":"spin1", "length":960, "scale":100}, {"name":"spin1", "length":960, "scale":100}, {"name":"spin1", "length":960, "scale":100}, {"name":"spin2", "length":960, "scale":100} ]}, where "spin1" is a 360 deg rotation, and "spin2" is the spin reverberation. (But of course, lane spins are not linear changes, so I don't think this example simply works well.)

I don't think this is a good design because you need to set two macros for just using one spin. But I don't know how to improve it keeping the requirements of the lane swing and multiple spins fulfilled.