Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Beatmap/BeatmapPlayback refactor #515

Merged
merged 7 commits into from
Jan 8, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 96 additions & 43 deletions Beatmap/include/Beatmap/Beatmap.hpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include "BeatmapObjects.hpp"
#include "AudioEffects.hpp"
#include "EffectTimeline.hpp"

/* Global settings stored in a beatmap */
struct BeatmapSettings
Expand Down Expand Up @@ -57,66 +58,118 @@ struct BeatmapSettings
class Beatmap : public Unique
{
public:
virtual ~Beatmap();
Beatmap() = default;
Beatmap(Beatmap&& other);
Beatmap& operator=(Beatmap&& other);
// Vector interacts badly with unique_ptr, so std::vector was used instead.
using Objects = std::vector<std::unique_ptr<ObjectState>>;
using ObjectsIterator = Objects::const_iterator;

using TimingPoints = Vector<TimingPoint>;
using TimingPointsIterator = TimingPoints::const_iterator;

using LaneTogglePoints = Vector<LaneHideTogglePoint>;
using LaneTogglePointsIterator = LaneTogglePoints::const_iterator;

public:
bool Load(BinaryStream& input, bool metadataOnly = false);
// Saves the map as it's own format
bool Save(BinaryStream& output) const;

// Returns the settings of the map, contains metadata + song/image paths.
/// Returns the settings of the map, contains metadata + song/image paths.
const BeatmapSettings& GetMapSettings() const;

// Vector of timing points in the map, sorted by when they appear in the map
// Must keep the beatmap class instance alive for these to stay valid
// Can contain multiple objects at the same time
const Vector<TimingPoint*>& GetLinearTimingPoints() const;
// Vector of chart stops in the chart, sorted by when they appear in the map
// Must keep the beatmap class instance alive for these to stay valid
// Can contain multiple objects at the same time
const Vector<ChartStop*>& GetLinearChartStops() const;
// Vector of objects in the map, sorted by when they appear in the map
// Must keep the beatmap class instance alive for these to stay valid
// Can contain multiple objects at the same time
const Vector<ObjectState*>& GetLinearObjects() const;
// Vector of zoom control points in the map, sorted by when they appear in the map
// Must keep the beatmap class instance alive for these to stay valid
// Can contain multiple objects at the same time
const Vector<ZoomControlPoint*>& GetZoomControlPoints() const;

const Vector<LaneHideTogglePoint*>& GetLaneTogglePoints() const;

const Vector<String>& GetSamplePaths() const;

const Vector<String>& GetSwitchablePaths() const;

// Retrieves audio effect settings for a given button id
const Vector<LaneHideTogglePoint>& GetLaneTogglePoints() const { return m_laneTogglePoints; }

const Vector<String>& GetSamplePaths() const { return m_samplePaths; }
const Vector<String>& GetSwitchablePaths() const { return m_switchablePaths; }

/// Retrieves audio effect settings for a given button id
AudioEffect GetEffect(EffectType type) const;
// Retrieves audio effect settings for a given filter effect id
/// Retrieves audio effect settings for a given filter effect id
AudioEffect GetFilter(EffectType type) const;

// Get the timing of the last (non-event) object
/// Get the timing of the first (non-event) object
MapTime GetFirstObjectTime(MapTime lowerBound) const;
/// Get the timing of the last (non-event) object
MapTime GetLastObjectTime() const;
/// Get the timing of the last object, including the event objects
MapTime GetLastObjectTimeIncludingEvents() const;

// Measure -> Time
/// Measure -> Time
MapTime GetMapTimeFromMeasureInd(int measure) const;
// Time -> Measure
/// Time -> Measure
int GetMeasureIndFromMapTime(MapTime time) const;

/// Computes the most frequently occuring BPM (to be used for MMod)
double GetModeBPM() const;
void GetBPMInfo(double& startBPM, double& minBPM, double& maxBPM, double& modeBPM) const;

void Shuffle(int seed, bool random, bool mirror);
void ApplyShuffle(const std::array<int, 6>& swaps, bool flipLaser);

/// # of (4th-note) beats between the start and the end
float GetBeatCount(MapTime start, MapTime end, TimingPointsIterator hint) const;
float GetBeatCountWithScrollSpeedApplied(MapTime start, MapTime end, TimingPointsIterator hint) const;

inline float GetBeatCount(MapTime start, MapTime end) const
{
return GetBeatCount(start, end, GetTimingPoint(start));
}

inline float GetBeatCountWithScrollSpeedApplied(MapTime start, MapTime end) const
{
return GetBeatCountWithScrollSpeedApplied(start, end, GetTimingPoint(start));
}

const Objects& GetObjectStates() const { return m_objectStates; }

ObjectsIterator GetFirstObjectState() const { return m_objectStates.begin(); }
ObjectsIterator GetEndObjectState() const { return m_objectStates.end(); }

bool HasObjectState() const { return !m_objectStates.empty(); }

const TimingPoints& GetTimingPoints() const { return m_timingPoints; }

TimingPointsIterator GetFirstTimingPoint() const { return m_timingPoints.begin(); }
TimingPointsIterator GetEndTimingPoint() const { return m_timingPoints.end(); }

/// Returns the latest timing point for given mapTime
inline TimingPointsIterator GetTimingPoint(MapTime mapTime) const
{
return GetTimingPoint(mapTime, 0, m_timingPoints.size());
}

/// GetTimingPoint but a hint is given
TimingPointsIterator GetTimingPoint(MapTime mapTime, TimingPointsIterator hint, bool forwardOnly = false) const;

/// GetTimingPoint but begin and end ranges are specified
inline TimingPointsIterator GetTimingPoint(MapTime mapTime, TimingPointsIterator beginIt, TimingPointsIterator endIt) const
{
return GetTimingPoint(mapTime, static_cast<size_t>(std::distance(m_timingPoints.begin(), beginIt)), static_cast<size_t>(std::distance(m_timingPoints.begin(), endIt)));
}

TimingPointsIterator GetTimingPoint(MapTime mapTime, size_t begin, size_t end) const;

LaneTogglePointsIterator GetFirstLaneTogglePoint() const { return m_laneTogglePoints.begin(); }
LaneTogglePointsIterator GetEndLaneTogglePoint() const { return m_laneTogglePoints.end(); }

float GetGraphValueAt(EffectTimeline::GraphType type, MapTime mapTime) const;
bool CheckIfManualTiltInstant(MapTime bound, MapTime mapTime) const;

float GetCenterSplitValueAt(MapTime mapTime) const;
float GetScrollSpeedAt(MapTime mapTime) const;

private:
bool m_ProcessKShootMap(BinaryStream& input, bool metadataOnly);
bool m_Serialize(BinaryStream& stream, bool metadataOnly);

Map<EffectType, AudioEffect> m_customEffects;
Map<EffectType, AudioEffect> m_customFilters;
Map<EffectType, AudioEffect> m_customAudioEffects;
Map<EffectType, AudioEffect> m_customAudioFilters;

Objects m_objectStates;
TimingPoints m_timingPoints;

EffectTimeline m_effects;

LineGraph m_centerSplit;
Vector<LaneHideTogglePoint> m_laneTogglePoints;
Map<String, Map<MapTime, String>> m_positionalOptions;

Vector<TimingPoint*> m_timingPoints;
Vector<ChartStop*> m_chartStops;
Vector<LaneHideTogglePoint*> m_laneTogglePoints;
Vector<ObjectState*> m_objectStates;
Vector<ZoomControlPoint*> m_zoomControlPoints;
Vector<String> m_samplePaths;
Vector<String> m_switchablePaths;
BeatmapSettings m_settings;
Expand Down
57 changes: 17 additions & 40 deletions Beatmap/include/Beatmap/BeatmapObjects.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ struct TObjectState<void> : public ObjectTypeData_Base
TObjectState() : ObjectTypeData_Base(ObjectType::Invalid){};

// Sort object states by their time and other properties
static void SortArray(Vector<TObjectState<void> *> &arr);
static void SortArray(std::vector<std::unique_ptr<TObjectState<void>>>& arr);

// Always allow casting from typeless object to Union State object
operator MultiObjectState *() { return (MultiObjectState *)this; }
Expand Down Expand Up @@ -180,9 +180,14 @@ struct SpinStruct
struct ObjectTypeData_Laser
{
// Retrieves the starting laser point
TObjectState<ObjectTypeData_Laser> *GetRoot();
TObjectState<ObjectTypeData_Laser>* GetRoot();
inline const TObjectState<ObjectTypeData_Laser>* GetRoot() const
{
return const_cast<ObjectTypeData_Laser*>(this)->GetRoot();
}

// Ending point of laser
TObjectState<ObjectTypeData_Laser> *GetTail();
TObjectState<ObjectTypeData_Laser>* GetTail();
float GetDirection() const;
float SamplePosition(MapTime time) const;
// Convert extended range to normal range
Expand Down Expand Up @@ -300,50 +305,22 @@ struct TimingPoint
double GetBarDuration() const { return GetWholeNoteLength() * ((double)numerator / (double)denominator); }
double GetBPM() const { return 60000.0 / beatDuration; }

// Position in ms when this timing point appears
/// Position in ms when this timing point appears
MapTime time = 0;
// Beat duration of a 4th note in milliseconds
// this is a double so the least precision is lost
// can be cast back to integer format once is has been multiplied by the amount of beats you want the length of.
// Calculated by taking (60000.0 / BPM)
/// Beat duration of a 4th note in milliseconds (equals 60000.0 / BPM)
double beatDuration;
// Upper part of the time signature
// how many beats per bar
/// Upper part of the time signature (how many beats per bar)
uint8 numerator = 4;
// Lower part of the time signature
// the note value (4th, 3th, 8th notes, etc.) for a beat
/// Lower part of the time signature (the note value (4th, 3th, 8th notes, etc.) for a beat)
uint8 denominator = 4;
/// Multiplier for tickrates (x 2^tickrateOffset)
int8 tickrateOffset = 0;
};

struct LaneHideTogglePoint
{
// Position in ms when to hide or show the lane
struct LaneHideTogglePoint {
/// Position in ms when to hide or show the lane
MapTime time;

// How long the transition to/from hidden should take in 1/192nd notes
/// How long the transition to/from hidden should take in 1/192nd notes
uint32 duration = 192;
};

// Control point for track zoom levels
struct ZoomControlPoint
{
MapTime time;
// What zoom to control
// 0 = bottom
// 1 = top
uint8 index = 0;
// The zoom value
// in the range -1 to 1
// 1 being fully zoomed in
float zoom = 0.0f;
// Used to check if a manual tilt assignment is instant
bool instant = false;
};

// Chart stop object
struct ChartStop
{
MapTime time;
MapTime duration;
};
};
Loading