Skip to content

Commit

Permalink
[Docs] Improved docs on tempo map
Browse files Browse the repository at this point in the history
  • Loading branch information
melanchall committed Jun 11, 2022
1 parent 7dc6323 commit 9382437
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 75 deletions.
57 changes: 1 addition & 56 deletions Docs/articles/high-level-managing/Objects-managers.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,59 +70,4 @@ var notesManager = new TimedObjectsManager<Note>(trackChunk.Events);
timedEventsManager.SaveChanges();
```

will cause changes made with the `notesManager` will be lost because `SaveChanges` (or `Dispose` in first code snippet) of `timedEventsManager` executed after `SaveChanges` of `notesManager`, and thus rewrites underlying events collection. You need to save changes made with a previous manager before managing objects with next one.

## Tempo map

Tempo map is a set of changes of time signature and tempo. You need to have a tempo map to convert [time and length](Time-and-length.md) between different representations. Instead of messing with [Time Signature](xref:Melanchall.DryWetMidi.Core.TimeSignatureEvent) and [Set Tempo](xref:Melanchall.DryWetMidi.Core.SetTempoEvent) events DryWetMIDI provides [TempoMapManager](xref:Melanchall.DryWetMidi.Interaction.TempoMapManager) which helps to manage tempo map of a MIDI file:

```csharp
using (var tempoMapManager = new TempoMapManager(midiFile.TimeDivision,
midiFile.GetTrackChunks()
.Select(c => c.Events)))
{
TempoMap tempoMap = tempoMapManager.TempoMap;

Tempo tempoAt123 = tempoMap.GetTempoAtTime((MidiTimeSpan)123);

// Change tempo to 400000 microseconds per quarter note at 20 seconds from
// MIDI file start
tempoMapManager.SetTempo(new MetricTimeSpan(0, 0, 20), new Tempo(400000));

tempoMapManager.ClearTimeSignature(456);
}
```

To get tempo map being managed by the current `TempoMapManager` you need to use [TempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMapManager.TempoMap) property which returns an instance of the [TempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMap) class.

Once you've got an instance of [TempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMap) you can use [GetTempoChanges](xref:Melanchall.DryWetMidi.Interaction.TempoMap.GetTempoChanges) method to get all tempo changes. Use [GetTimeSignatureChanges](xref:Melanchall.DryWetMidi.Interaction.TempoMap.GetTimeSignatureChanges) method to get time signature changes. [GetTempoAtTime](xref:Melanchall.DryWetMidi.Interaction.TempoMap.GetTempoAtTime(Melanchall.DryWetMidi.Interaction.ITimeSpan)) and [GetTimeSignatureAtTime](xref:Melanchall.DryWetMidi.Interaction.TempoMap.GetTimeSignatureAtTime(Melanchall.DryWetMidi.Interaction.ITimeSpan)) methods allow to get tempo and time signature at the specified time.

You can also create new tempo map with `TempoMapManager`:

```csharp
using (var tempoMapManager = new TempoMapManager())
{
// ...
}
```

There is another way to get an instance of the `TempoMapManager` – through the [ManageTempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMapManagingUtilities.ManageTempoMap*) extension method:

```csharp
using (var tempoMapManager = midiFile.ManageTempoMap())
{
// ...
}
```

This method and another useful ones are placed in [TempoMapManagingUtilities](xref:Melanchall.DryWetMidi.Interaction.TempoMapManagingUtilities). For example, to get tempo map of a MIDI file you can write:

```csharp
TempoMap tempoMap = midiFile.GetTempoMap();
```

Also you can replace the entire tempo map of a MIDI file using [ReplaceTempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMapManagingUtilities.ReplaceTempoMap*) method:

```csharp
midiFile.ReplaceTempoMap(TempoMap.Create(Tempo.FromBeatsPerMinute(140)));
```
will cause changes made with the `notesManager` will be lost because `SaveChanges` (or `Dispose` in first code snippet) of `timedEventsManager` executed after `SaveChanges` of `notesManager`, and thus rewrites underlying events collection. You need to save changes made with a previous manager before managing objects with next one.
66 changes: 66 additions & 0 deletions Docs/articles/high-level-managing/Tempo-map.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
uid: a_tempo_map
---

# Tempo map

Tempo map is a set of changes of time signature and tempo. Tempo map is one of the key objects in high-level managing of MIDI data. You need to have a tempo map to convert [time and length](Time-and-length.md) between different representations, either explicitly or internally at some parts of the library (for example, in [tools](xref:a_tools_overview)). Following image shows how tempo map constructed for a given set of events or MIDI file:

![Tempo map](images/TempoMap.png)

So as you can see tempo map doesn't reflect original MIDI events. Tempo map holds real tempo and time signature changes. Default tempo is 120 BPM by MIDI specifications so there is no need to hold first two tempo "changes" because tempo is not changed in fact. The same for time signature (which is `4/4` by default). Also any repeated values are ignored since they don't change tempo or time signature.

Instead of messing with [Time Signature](xref:Melanchall.DryWetMidi.Core.TimeSignatureEvent) and [Set Tempo](xref:Melanchall.DryWetMidi.Core.SetTempoEvent) events DryWetMIDI provides [TempoMapManager](xref:Melanchall.DryWetMidi.Interaction.TempoMapManager) which helps to manage tempo map of a MIDI file:

```csharp
using (var tempoMapManager = new TempoMapManager(
midiFile.TimeDivision,
midiFile.GetTrackChunks().Select(c => c.Events)))
{
TempoMap tempoMap = tempoMapManager.TempoMap;

Tempo tempoAt123 = tempoMap.GetTempoAtTime((MidiTimeSpan)123);

// Change tempo to 400000 microseconds per quarter note at 20 seconds from
// MIDI file start
tempoMapManager.SetTempo(new MetricTimeSpan(0, 0, 20), new Tempo(400000));

tempoMapManager.ClearTimeSignature(456);
}
```

To get tempo map being managed by the current `TempoMapManager` you need to use [TempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMapManager.TempoMap) property which returns an instance of the [TempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMap) class.

Once you've got an instance of [TempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMap) you can use [GetTempoChanges](xref:Melanchall.DryWetMidi.Interaction.TempoMap.GetTempoChanges) method to get all tempo changes. Use [GetTimeSignatureChanges](xref:Melanchall.DryWetMidi.Interaction.TempoMap.GetTimeSignatureChanges) method to get time signature changes. [GetTempoAtTime](xref:Melanchall.DryWetMidi.Interaction.TempoMap.GetTempoAtTime(Melanchall.DryWetMidi.Interaction.ITimeSpan)) and [GetTimeSignatureAtTime](xref:Melanchall.DryWetMidi.Interaction.TempoMap.GetTimeSignatureAtTime(Melanchall.DryWetMidi.Interaction.ITimeSpan)) methods allow to get tempo and time signature at the specified time.

You can also create new tempo map with `TempoMapManager`:

```csharp
using (var tempoMapManager = new TempoMapManager())
{
// ...
}
```

If you want to create a simple tempo map with some fixed tempo or/and time signature without changes, use [Create](xref:Melanchall.DryWetMidi.Interaction.TempoMap.Create*) static methods of the `TempoMap` class.

There is another way to get an instance of the `TempoMapManager` – through the [ManageTempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMapManagingUtilities.ManageTempoMap*) extension method:

```csharp
using (var tempoMapManager = midiFile.ManageTempoMap())
{
// ...
}
```

This method and another useful ones are placed in [TempoMapManagingUtilities](xref:Melanchall.DryWetMidi.Interaction.TempoMapManagingUtilities). For example, to get tempo map of a MIDI file you can write:

```csharp
TempoMap tempoMap = midiFile.GetTempoMap();
```

Also you can replace the entire tempo map of a MIDI file using [ReplaceTempoMap](xref:Melanchall.DryWetMidi.Interaction.TempoMapManagingUtilities.ReplaceTempoMap*) method:

```csharp
midiFile.ReplaceTempoMap(TempoMap.Create(Tempo.FromBeatsPerMinute(140)));
```
Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions Docs/articles/toc.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

# High-level data managing
## [Objects managers](high-level-managing/Objects-managers.md)
## [Tempo map](high-level-managing/Tempo-map.md)
## [Time and length](high-level-managing/Time-and-length.md)
## [Getting objects](high-level-managing/Getting-objects.md)

Expand Down
3 changes: 1 addition & 2 deletions DryWetMidi/Interaction/TempoMap/TempoMap.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
namespace Melanchall.DryWetMidi.Interaction
{
/// <summary>
/// Represents a tempo map of a MIDI file. More info in the
/// <see href="xref:a_managers#tempo-map">Objects managers: Tempo map</see> article.
/// Represents a tempo map of a MIDI file. More info in the <see href="xref:a_tempo_map">Tempo map</see> article.
/// </summary>
public sealed class TempoMap
{
Expand Down
12 changes: 1 addition & 11 deletions DryWetMidi/Interaction/TempoMap/TempoMapManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,8 @@
namespace Melanchall.DryWetMidi.Interaction
{
/// <summary>
/// Provides a way to manage tempo map of a MIDI file. More info in the
/// <see href="xref:a_managers#tempo-map">Objects managers: Tempo map</see> article.
/// Provides a way to manage tempo map of a MIDI file. More info in the <see href="xref:a_tempo_map">Tempo map</see> article.
/// </summary>
/// <remarks>
/// This manager is wrapper for the <see cref="TimedEventsManager"/> that provides easy manipulation
/// of specific MIDI events: <see cref="SetTempoEvent"/> and <see cref="TimeSignature"/>. Also it
/// provides <see cref="TempoMap"/> that can be used to calculate custom representations of time
/// and length of an object. To start manage tempo map you need to get an instance of the
/// <see cref="TempoMapManager"/>. To finish managing you need to call the <see cref="SaveChanges"/>
/// or <see cref="Dispose()"/> method. Since the manager implements <see cref="IDisposable"/> it is
/// recommended to manage tempo map within using block.
/// </remarks>
/// <seealso cref="Interaction.TempoMap"/>
public sealed class TempoMapManager : IDisposable
{
Expand Down
10 changes: 4 additions & 6 deletions DryWetMidi/Interaction/TempoMap/TempoMapManagingUtilities.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@
namespace Melanchall.DryWetMidi.Interaction
{
/// <summary>
/// Extension methods for managing tempo map.
/// Extension methods for managing tempo map. More info in the <see href="xref:a_tempo_map">Tempo map</see> article.
/// </summary>
public static class TempoMapManagingUtilities
{
#region Methods

/// <summary>
/// Creates an instance of the <see cref="TempoMapManager"/> initializing it with the
/// specified events collections and time division. More info in the
/// <see href="xref:a_managers#tempo-map">Objects managers: Tempo map</see> article.
/// specified events collections and time division. More info in the <see href="xref:a_tempo_map">Tempo map</see> article.
/// </summary>
/// <param name="eventsCollections">Collection of <see cref="EventsCollection"/> which hold events
/// that represent tempo map of a MIDI file.</param>
Expand Down Expand Up @@ -46,7 +45,7 @@ public static TempoMapManager ManageTempoMap(this IEnumerable<EventsCollection>
/// <summary>
/// Creates an instance of the <see cref="TempoMapManager"/> initializing it with the
/// specified time division and events collections of the specified track chunks. More info in the
/// <see href="xref:a_managers#tempo-map">Objects managers: Tempo map</see> article.
/// <see href="xref:a_tempo_map">Tempo map</see> article.
/// </summary>
/// <param name="trackChunks">Collection of <see cref="TrackChunk"/> which hold events
/// that represent tempo map of a MIDI file.</param>
Expand Down Expand Up @@ -75,8 +74,7 @@ public static TempoMapManager ManageTempoMap(this IEnumerable<TrackChunk> trackC

/// <summary>
/// Creates an instance of the <see cref="TempoMapManager"/> initializing it with the
/// events collections of the specified MIDI file. More info in the
/// <see href="xref:a_managers#tempo-map">Objects managers: Tempo map</see> article.
/// events collections of the specified MIDI file. More info in the <see href="xref:a_tempo_map">Tempo map</see> article.
/// </summary>
/// <param name="file">MIDI file to manage tempo map of.</param>
/// <returns>An instance of the <see cref="TempoMapManager"/> that can be used to manage
Expand Down

0 comments on commit 9382437

Please sign in to comment.