Skip to content

Commit

Permalink
Beatmap/BeatmapPlayback refactor #515
Browse files Browse the repository at this point in the history
  • Loading branch information
Drewol authored Jan 8, 2022
2 parents d1a52bc + ffeaa02 commit 4062a25
Show file tree
Hide file tree
Showing 27 changed files with 1,783 additions and 1,262 deletions.
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

0 comments on commit 4062a25

Please sign in to comment.