【TidalCycles】サイクル数を表示する方法

# はじめに

TidalCyclesはシンセや音源を用いてトラックを気軽に作れるためとても便利です。
ただ、個人的には

- 0サイクル目から再生する方法
- サイクル数を表示する方法

が~~[公式ページ](https://tidalcycles.org/)で明示されていないため、少し使いづらいところがありました。~~(**[公式](https://tidalcycles.org/docs/reference/cycles#pop-up-window)でサイクル数をPop-up windowで表示する方法が紹介されてました。後述します**)

今回は「**サイクル数を表示する方法**」について紹介したいと思います。(「0サイクル目から再生する方法」については別記事で紹介しています。)

https://qiita.com/mynkit/items/88ab4ebb45882f7b339d

<details>
<summary>泥臭すぎるやり方</summary>

~~※ここで紹介する手法は割と泥臭く拡張性のないやりかたなので、直接サイクル数を知れる方法をご存知の方がいれば教えてください！~~(※後述)

# StateValueの中身を表示する方法

TidalCyclesのversion1.7.2からはStateValueというものが使えるようになっています。詳細は[公式ページ](https://tidalcycles.org/docs/reference/state_values)を確認してみてください。

このStateValueなんですが、中身を確認する方法があるみたいです。

https://club.tidalcycles.org/t/working-with-tidal-state-values-tidal-can-count/2955/7

```haskell
import Control.Concurrent.MVar

import Data.Map as Map

d2 $ every 2 (+ nCount "i") $ s "sn*3"

fmap (Map.lookup "i") (readMVar $ sStateMV tidal)
```

上のように、d2が再生されている間はStateValueである`i`が再生されるごとに増えていきます。

`fmap (Map.lookup "i") (readMVar $ sStateMV tidal)`を実行するたびにコンソールに`i`の値が表示されます

# サイクル数を表示する方法

これと、[0サイクル目から再生する方法](https://qiita.com/mynkit/items/88ab4ebb45882f7b339d)で紹介した`resetCyclesTo`関数を用いることによってサイクル数が取得できそうです。


```haskell
do
  resetCyclesTo (-0.05)
  setF "i" 0
  d16 $ (+ nCount "i") $ s "sn" # gain 0
```

これを実行することによって、

- 0サイクル目からスタート
- StateValue`i`を0に初期化
- 1サイクルごとに`sn`がVolume0で再生され、その度に`i`が1ずつ増えていく

ということになります。

したがって、`fmap (Map.lookup "i") (readMVar $ sStateMV tidal)`を実行すると、サイクル数を確認することができます。

全体のコードはこんな感じになります(d1,d2,d3はサンプルとして載せただけなのでお好きなトラックを作ってください！)

```haskell
import qualified Sound.Tidal.Tempo as T

resetCyclesTo n = T.changeTempo (sTempoMV tidal) (\t tempo -> tempo {T.atTime = t, T.atCycle = n})

import Control.Concurrent.MVar

import Data.Map as Map

fmap (Map.lookup "i") (readMVar $ sStateMV tidal)

do
  -- resetCyclesTo (-0.05)
  -- setF "i" 0
  d1 $ s "{808sd:11*3,808oh*4}"
  d2 $ s "~ 909 ~ 909"
  d3 $ s "superhammond" # n "<d4,e4,a4,cs5>" # sustain 0.2 # voice 1
  d16 $ (+ nCount "i") $ s "sn" # gain 0
```

`resetCyclesTo (-0.05)`と`setF "i" 0`は再生開始時のみ実行で、再生直後にはコメントアウトしてください(でないと、次の実行時に再生がリセットされて0サイクル目から再生されます)


# この手法の弱点

弱点というか注意点がいくつかあるのでまとめておきます

- 再生直後に`resetCyclesTo (-0.05)`と`setF "i" 0`をコメントアウトするの忘れると次の実行時に恥ずかしい
- d16を占領してしまう
- d16が再生停止すると、Tidal内部におけるサイクル数は増えていくのに、`i`は更新されなくなる


</details>


# エディタから表示させる方法

```haskell
streamGetnow tidal
```
で、小数点付きのサイクル数が得られる

# 【公式のやり方】サイクル数をPop-up windowで表示する方法

[公式のreferenceページ](https://tidalcycles.org/docs/reference/cycles#pop-up-window)が更新され、もっと良い方法が紹介されていました。

superdirtを起動させてから、

```supercollider
(
var clockMods, clockBeats, screenW, screenH, clockW, clockH, clockX, clockY, resizable, border;
clockMods = [4,6];
clockBeats = 4;
screenW = 1440;
screenH = 900;
clockW = 120;
clockH = 22;
clockX = screenW - clockW;
clockY = screenH - 1;
resizable = false;
border = false;

~clockText = StaticText()
.string_("[clock]")
.font_(Font.defaultMonoFace)
.align_(\center)
.stringColor_(Color(1,1,1))
.minHeight_(20);

~updateClock = { |cycle|
    var text, beat;
    text = clockMods.collect { |m| "" ++ (cycle.floor.asInteger.mod(m) + 1) ++ "/" ++ m; }.join(" ");
    beat = (cycle.mod(1)*clockBeats).round.asInteger + 1;
    text = text ++ " " ++ clockBeats.collect { |i| if(i < beat, ".", " "); }.join;
    ~clockText.string_(text);
};

~clockWindow = Window("clock", Rect(clockX, clockY, clockW, clockH), resizable, border)
.background_(Color(0.3,0.3,0.3))
.layout_(
    HLayout(
        ~clockText
    ).margins_(0!4)
);

~clockWindow.alwaysOnTop_(true);
~clockWindow.visible_(true);

SynthDef(\tick, { |cycle|
    SendReply.kr(Impulse.kr(0), "/tick", [cycle]);
    FreeSelf.kr(Impulse.kr(0));
}).add;

OSCdef(\tick, { |msg|
    var cycle;
    #cycle = msg[3..];
    Routine {
        { ~updateClock.(cycle); }.defer;
    }.play(SystemClock);
}, "/tick");
)
```
を実行して、TidalCyclces側で

```haskell
p "tick" $ "0*4" # s "tick"
```

を実行するだけです。

個人的には16サイクルのうちのサイクル数がみたいことが多いので、`clockMods = [4,6];`を`clockMods = [16];`に変えれば知りたいものが見れました。

文字サイズは割と小さく、右上にこんな感じで表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437488/684124a2-9bd3-fdd1-65a7-1e2e4da24ce8.png)

こんな感じで、リアルタイムでサイクル数を確認できます。

![showcycles.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/437488/8ceff933-1073-7329-68c5-09688c53a038.gif)