Ryle Radio 1.0.0
An open-source "radio" system for Unity, allowing tracks, tuning, broadcasters, and more!
Loading...
Searching...
No Matches
StationRadioTrack.cs
1using System;
2using System.Collections.Generic;
3using UnityEngine;
4
5namespace RyleRadio.Tracks
6{
7
8 /// <summary>
9 /// A eventType of RadioTrack that contains other tracks. Has a custom editor in \ref StationRadioTrackEditor<br>
10 /// This is meant to emulate an actual radio station by storing multiple different tracks and switching between them as it plays.
11 /// It can be used for really any purpose that calls for switching tracks, though- e.g: ''''procedural'''' music, complex ambience, easter eggs (kinda)
12 ///
13 /// Also uses \ref StationRadioTrackWrapper
14 /// </summary>
15 [System.Serializable]
17 {
18 /// <summary>
19 /// The display name of this track in the editor. Required by \ref RadioTrack
20 /// </summary>
21 public const string DISPLAY_NAME = "Station aka Multi-select";
22
23 /// <summary>
24 /// Whether or not this station plays in a random or semi-random order
25 /// </summary>
26 public bool randomSequence = true;
27
28 /// <summary>
29 /// When \ref randomSequence is true, this is the number of other tracks that need to be played before the same one is chosen again. Stops the same track from playing back-to-back, and forces variety in the track order.
30 ///
31 /// The number of tracks to be played before one can be played again is `round_down( (track_count - 1) * threshold )`.
32 /// <br>i.e with four tracks and a threshold of 0.5f, `round_down((4 - 1 == 3) * 0.5) == 1`: one other track will need to be played before a repeat
33 /// <br>i.e with four tracks and a threshold of 0.7f, `round_down((4 - 1 == 3) * 0.7) == 2`: two other tracks will need to be played before a repeat
34 /// <br>i.e with four tracks and a threshold of 1f, `round_down((4 - 1 == 3) * 1) == 3`: three other tracks (all other tracks) will need to be played before a repeat
35 /// <br>i.e with eleven tracks and a threshold of 0.8f, `round_down((11 - 1 == 10) * 0.8f == 8`: eight other tracks will need to be played before a repeat
36 /// <i>Do note that if this is set to 1, the tracks are forced to play in the same randomized sequence repeatedly</i>
37 /// </summary>
39
40 /// <summary>
41 /// The tracks contained within this station
42 /// </summary>
43 public List<StationRadioTrackWrapper> stationTrackWs;
44
45 /// <summary>
46 /// The index of the contained track that's currently playing
47 /// </summary>
48 private int currentTrackIndex;
49
50#if !SKIP_IN_DOXYGEN
51 // audio is on a separate threat to UnityEngine.Random so we need to use System.Random instead
52 private System.Random random;
53#endif
54
55 /// <summary>
56 /// The number of plays that need to happen before each track can be played again. Follows the layout described in \ref thresholdBeforeRepeats
57 ///
58 /// i.e if tracks A, B and C are being randomly chosen with a \ref thresholdBeforeRepeats of 0.5f, they each need to have 1 other track play before each can repeat (see comments above thresholdBeforeRepeats)
59 /// <br>So if track A was just played after B and C, this array would look like [1, 0, -1].
60 /// That is, track A needs another track to be played once before it can be repeated, B doesn't need any other tracks to play and thus can be repeated, and same for C
61 /// <br><i>(a number below 0 is treated as 0 for this system)</i><br><br>
62 /// <b>See:</b> \ref NextTrack()
63 /// </summary>
65
66#if !SKIP_IN_DOXYGEN
67 // if this track has no stations, we want to print an error- but only once, otherwise it freezes the editor
68 private bool hasPrintedError;
69#endif
70
71 /// <summary>
72 /// A reference to the track that's currently playing
73 /// </summary>
75
76
77 /// <summary>
78 /// Initializes this station and all contained tracks
79 /// </summary>
80 public override void Init()
81 {
82 random = new System.Random();
83
84 // creates an entry for every track
87
88 hasPrintedError = false;
89
90 // initializes all child tracks
92 trackW.Init();
93
94 // selects the first track to play
95 NextTrack();
96 }
97
98 /// <summary>
99 /// When a RadioTrackPlayer for this station finishes the track we've given it, we update it to use whatever the next track chosen is. This method is called when the Player finishes, so we update it here.
100 /// This works because the Player only gets destroyed if it's a one-shot- in which case only one track from the station will be playing anyway
101 /// </summary>
102 /// <param name="_callback">The callback invoked when the \ref RadioTrackPlayer ends</param>
103 public override void AddToPlayerEndCallback(ref Action<RadioTrackPlayer> _callback)
104 {
105 _callback += p => NextTrack(); // choose the next track when the Player completes the last one
106 _callback += p => p.UpdateSampleIncrement(); // update the Player's SampleCount/Length when the next track is chosen
107 }
108
109 /// <summary>
110 /// Gets a sample from the currently playing track
111 /// </summary>
112 /// <param name="_sampleIndex">The index of the sample</param>
113 /// <returns>A sample from \ref CurrentTrackW</returns>
114 public override float GetSample(int _sampleIndex)
115 {
116 // get the sample from the currently playing track
117 // station tracks also have their own gain variable so apply that
118 return CurrentTrackW.GetSample(_sampleIndex) * CurrentTrackW.Gain;
119 }
120
121 /// <summary>
122 /// Selects the next track for this station to play
123 /// </summary>
124 private void NextTrack()
125 {
126 // if there aren't any stations, alert the player and stop trying to get them
127 if (stationTrackWs.Count == 0)
128 {
129 // if the error hasn't been printed, print it
130 if (!hasPrintedError)
131 {
132 Debug.LogWarning($"Cannot play a StationRadioTrack, as there are no stations!");
133 hasPrintedError = true;
134 }
135
136 // otherwise stop
137 return;
138 }
139
140 // if the next track is randomly chosen
141 if (randomSequence)
142 {
143 // make a list for all of the tracks that can be chosen this time
144 List<int> selectFrom = new();
145
146 // find all tracks that can be played right now, and store their index from stationTrackWs
147 for (int i = 0; i < remainingTracksBeforeRepeat.Length; i++)
148 {
149 // if a track has <=0 tracks remaining before it can be played, then it can be played
150 if (remainingTracksBeforeRepeat[i] <= 0)
151 selectFrom.Add(i);
152 }
153
154 // select one track from the playable tracks
155 int trackIndex = selectFrom[random.Next(0, selectFrom.Count)];
156
157 // if each track needs to wait for a certain amount of other plays before it can be played again,
159 {
160 // decrement the amount of plays each track needs before it can be played again
161 for (int t = 0; t < remainingTracksBeforeRepeat.Length; t++)
163
164 // set the selected track's amount to the maximum number (threshold * track count)
165 remainingTracksBeforeRepeat[trackIndex] = (int)((stationTrackWs.Count - 1) * thresholdBeforeRepeats);
166 }
167
168 // assign the chosen track
169 currentTrackIndex = trackIndex;
170 }
171 // otherwise if the station uses a set sequence
172 else
173 {
174 // increment the index
176
177 // if the end of the station is reached, go back to the first track
180 }
181
182 // assign the sample data based on the newly chosen track
183 SampleRate = CurrentTrackW.SampleRate;
184 SampleCount = CurrentTrackW.SampleCount;
185 }
186 }
187
188}
A track to play as part of a radio. These are the fundamental objects that define the content of the ...
Definition RadioTrack.cs:20
float SampleRate
The sample rate of this track.
Definition RadioTrack.cs:27
virtual int SampleCount
The number of samples in this track.
Definition RadioTrack.cs:33
A eventType of RadioTrack that contains other tracks. Has a custom editor in StationRadioTrackEditor ...
float thresholdBeforeRepeats
When randomSequence is true, this is the number of other tracks that need to be played before the sam...
StationRadioTrackWrapper CurrentTrackW
A reference to the track that's currently playing.
override float GetSample(int _sampleIndex)
Gets a sample from the currently playing track.
int[] remainingTracksBeforeRepeat
The number of plays that need to happen before each track can be played again. Follows the layout des...
override void Init()
Initializes this station and all contained tracks.
override void AddToPlayerEndCallback(ref Action< RadioTrackPlayer > _callback)
When a RadioTrackPlayer for this station finishes the track we've given it, we update it to use whate...
bool randomSequence
Whether or not this station plays in a random or semi-random order.
int currentTrackIndex
The index of the contained track that's currently playing.
List< StationRadioTrackWrapper > stationTrackWs
The tracks contained within this station.
const string DISPLAY_NAME
The display name of this track in the editor. Required by RadioTrack.
void NextTrack()
Selects the next track for this station to play.
A smaller, separate version of RadioTrackWrapper for use in a StationRadioTrack.
void Init()
Initialize the track stored in this wrapper.
Tracks to be used on a radio- includes base classes.
Definition RadioUtils.cs:20