prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  A few questions...
  I came across a few confusions while I was reading the code in order to write an example. It would be helpful for me if they are clarified ( I may have missed something).
  
  https://github.com/lhotse-speech/lhotse/blob/master/lhotse/kaldi.py#L68
  why `duration - start` rather than just `duration`?
  
  https://github.com/lhotse-speech/lhotse/blob/master/lhotse/audio.py#L178
  why not `[n_sources, n_channels, n_samples]`?
  
  Thanks!
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `lhotse/kaldi.py`
  Content:
  ```
  1 from collections import defaultdict
  2 from pathlib import Path
  3 from typing import Dict, Optional, Tuple
  4 
  5 from lhotse.audio import AudioSource, Recording, RecordingSet
  6 from lhotse.supervision import SupervisionSegment, SupervisionSet
  7 from lhotse.utils import Pathlike
  8 
  9 
  10 def load_kaldi_data_dir(path: Pathlike, sampling_rate: int) -> Tuple[RecordingSet, Optional[SupervisionSet]]:
  11     """
  12     Load a Kaldi data directory and convert it to a Lhotse RecordingSet and SupervisionSet manifests.
  13     For this to work, at least the wav.scp file must exist.
  14     SupervisionSet is created only when a segments file exists.
  15     All the other files (text, utt2spk, etc.) are optional, and some of them might not be handled yet.
  16     In particular, feats.scp files are ignored.
  17     """
  18     path = Path(path)
  19     assert path.is_dir()
  20 
  21     # must exist for RecordingSet
  22     recordings = load_kaldi_text_mapping(path / 'wav.scp', must_exist=True)
  23 
  24     durations = defaultdict(float)
  25     reco2dur = path / 'reco2dur'
  26     if not reco2dur.is_file():
  27         raise ValueError(f"No such file: '{reco2dur}' -- fix it by running: utils/data/get_reco2dur.sh <data-dir>")
  28     with reco2dur.open() as f:
  29         for line in f:
  30             recording_id, dur = line.strip().split()
  31             durations[recording_id] = float(dur)
  32 
  33     audio_set = RecordingSet.from_recordings(
  34         Recording(
  35             id=recording_id,
  36             sources=[
  37                 AudioSource(
  38                     type='command' if path_or_cmd.endswith('|') else 'file',
  39                     channels=[0],
  40                     source=path_or_cmd[:-1] if path_or_cmd.endswith('|') else path_or_cmd
  41                 )
  42             ],
  43             sampling_rate=sampling_rate,
  44             num_samples=int(durations[recording_id] * sampling_rate),
  45             duration=durations[recording_id]
  46         )
  47         for recording_id, path_or_cmd in recordings.items()
  48     )
  49 
  50     # must exist for SupervisionSet
  51     segments = path / 'segments'
  52     if not segments.is_file():
  53         return audio_set, None
  54 
  55     with segments.open() as f:
  56         supervision_segments = [l.strip().split() for l in f]
  57 
  58     texts = load_kaldi_text_mapping(path / 'text')
  59     speakers = load_kaldi_text_mapping(path / 'utt2spk')
  60     genders = load_kaldi_text_mapping(path / 'spk2gender')
  61     languages = load_kaldi_text_mapping(path / 'utt2lang')
  62 
  63     supervision_set = SupervisionSet.from_segments(
  64         SupervisionSegment(
  65             id=segment_id,
  66             recording_id=recording_id,
  67             start=float(start),
  68             duration=float(duration) - float(start),
  69             channel=0,
  70             text=texts[segment_id],
  71             language=languages[segment_id],
  72             speaker=speakers[segment_id],
  73             gender=genders[speakers[segment_id]]
  74         )
  75         for segment_id, recording_id, start, duration in supervision_segments
  76     )
  77 
  78     return audio_set, supervision_set
  79 
  80 
  81 def load_kaldi_text_mapping(path: Path, must_exist: bool = False) -> Dict[str, Optional[str]]:
  82     """Load Kaldi files such as utt2spk, spk2gender, text, etc. as a dict."""
  83     mapping = defaultdict(lambda: None)
  84     if path.is_file():
  85         with path.open() as f:
  86             mapping = dict(line.strip().split(' ', maxsplit=1) for line in f)
  87     elif must_exist:
  88         raise ValueError(f"No such file: {path}")
  89     return mapping
  90
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/lhotse/kaldi.py b/lhotse/kaldi.py
  --- a/lhotse/kaldi.py
  +++ b/lhotse/kaldi.py
  @@ -65,14 +65,14 @@
               id=segment_id,
               recording_id=recording_id,
               start=float(start),
  -            duration=float(duration) - float(start),
  +            duration=float(end) - float(start),
               channel=0,
               text=texts[segment_id],
               language=languages[segment_id],
               speaker=speakers[segment_id],
               gender=genders[speakers[segment_id]]
           )
  -        for segment_id, recording_id, start, duration in supervision_segments
  +        for segment_id, recording_id, start, end in supervision_segments
       )
   
       return audio_set, supervision_set
  
verification_info: {"golden_diff": "diff --git a/lhotse/kaldi.py b/lhotse/kaldi.py\n--- a/lhotse/kaldi.py\n+++ b/lhotse/kaldi.py\n@@ -65,14 +65,14 @@\n             id=segment_id,\n             recording_id=recording_id,\n             start=float(start),\n-            duration=float(duration) - float(start),\n+            duration=float(end) - float(start),\n             channel=0,\n             text=texts[segment_id],\n             language=languages[segment_id],\n             speaker=speakers[segment_id],\n             gender=genders[speakers[segment_id]]\n         )\n-        for segment_id, recording_id, start, duration in supervision_segments\n+        for segment_id, recording_id, start, end in supervision_segments\n     )\n \n     return audio_set, supervision_set\n", "issue": "A few questions...\nI came across a few confusions while I was reading the code in order to write an example. It would be helpful for me if they are clarified ( I may have missed something).\r\n\r\nhttps://github.com/lhotse-speech/lhotse/blob/master/lhotse/kaldi.py#L68\r\nwhy `duration - start` rather than just `duration`?\r\n\r\nhttps://github.com/lhotse-speech/lhotse/blob/master/lhotse/audio.py#L178\r\nwhy not `[n_sources, n_channels, n_samples]`?\r\n\r\nThanks!\n", "before_files": [{"content": "from collections import defaultdict\nfrom pathlib import Path\nfrom typing import Dict, Optional, Tuple\n\nfrom lhotse.audio import AudioSource, Recording, RecordingSet\nfrom lhotse.supervision import SupervisionSegment, SupervisionSet\nfrom lhotse.utils import Pathlike\n\n\ndef load_kaldi_data_dir(path: Pathlike, sampling_rate: int) -> Tuple[RecordingSet, Optional[SupervisionSet]]:\n    \"\"\"\n    Load a Kaldi data directory and convert it to a Lhotse RecordingSet and SupervisionSet manifests.\n    For this to work, at least the wav.scp file must exist.\n    SupervisionSet is created only when a segments file exists.\n    All the other files (text, utt2spk, etc.) are optional, and some of them might not be handled yet.\n    In particular, feats.scp files are ignored.\n    \"\"\"\n    path = Path(path)\n    assert path.is_dir()\n\n    # must exist for RecordingSet\n    recordings = load_kaldi_text_mapping(path / 'wav.scp', must_exist=True)\n\n    durations = defaultdict(float)\n    reco2dur = path / 'reco2dur'\n    if not reco2dur.is_file():\n        raise ValueError(f\"No such file: '{reco2dur}' -- fix it by running: utils/data/get_reco2dur.sh <data-dir>\")\n    with reco2dur.open() as f:\n        for line in f:\n            recording_id, dur = line.strip().split()\n            durations[recording_id] = float(dur)\n\n    audio_set = RecordingSet.from_recordings(\n        Recording(\n            id=recording_id,\n            sources=[\n                AudioSource(\n                    type='command' if path_or_cmd.endswith('|') else 'file',\n                    channels=[0],\n                    source=path_or_cmd[:-1] if path_or_cmd.endswith('|') else path_or_cmd\n                )\n            ],\n            sampling_rate=sampling_rate,\n            num_samples=int(durations[recording_id] * sampling_rate),\n            duration=durations[recording_id]\n        )\n        for recording_id, path_or_cmd in recordings.items()\n    )\n\n    # must exist for SupervisionSet\n    segments = path / 'segments'\n    if not segments.is_file():\n        return audio_set, None\n\n    with segments.open() as f:\n        supervision_segments = [l.strip().split() for l in f]\n\n    texts = load_kaldi_text_mapping(path / 'text')\n    speakers = load_kaldi_text_mapping(path / 'utt2spk')\n    genders = load_kaldi_text_mapping(path / 'spk2gender')\n    languages = load_kaldi_text_mapping(path / 'utt2lang')\n\n    supervision_set = SupervisionSet.from_segments(\n        SupervisionSegment(\n            id=segment_id,\n            recording_id=recording_id,\n            start=float(start),\n            duration=float(duration) - float(start),\n            channel=0,\n            text=texts[segment_id],\n            language=languages[segment_id],\n            speaker=speakers[segment_id],\n            gender=genders[speakers[segment_id]]\n        )\n        for segment_id, recording_id, start, duration in supervision_segments\n    )\n\n    return audio_set, supervision_set\n\n\ndef load_kaldi_text_mapping(path: Path, must_exist: bool = False) -> Dict[str, Optional[str]]:\n    \"\"\"Load Kaldi files such as utt2spk, spk2gender, text, etc. as a dict.\"\"\"\n    mapping = defaultdict(lambda: None)\n    if path.is_file():\n        with path.open() as f:\n            mapping = dict(line.strip().split(' ', maxsplit=1) for line in f)\n    elif must_exist:\n        raise ValueError(f\"No such file: {path}\")\n    return mapping\n", "path": "lhotse/kaldi.py"}], "after_files": [{"content": "from collections import defaultdict\nfrom pathlib import Path\nfrom typing import Dict, Optional, Tuple\n\nfrom lhotse.audio import AudioSource, Recording, RecordingSet\nfrom lhotse.supervision import SupervisionSegment, SupervisionSet\nfrom lhotse.utils import Pathlike\n\n\ndef load_kaldi_data_dir(path: Pathlike, sampling_rate: int) -> Tuple[RecordingSet, Optional[SupervisionSet]]:\n    \"\"\"\n    Load a Kaldi data directory and convert it to a Lhotse RecordingSet and SupervisionSet manifests.\n    For this to work, at least the wav.scp file must exist.\n    SupervisionSet is created only when a segments file exists.\n    All the other files (text, utt2spk, etc.) are optional, and some of them might not be handled yet.\n    In particular, feats.scp files are ignored.\n    \"\"\"\n    path = Path(path)\n    assert path.is_dir()\n\n    # must exist for RecordingSet\n    recordings = load_kaldi_text_mapping(path / 'wav.scp', must_exist=True)\n\n    durations = defaultdict(float)\n    reco2dur = path / 'reco2dur'\n    if not reco2dur.is_file():\n        raise ValueError(f\"No such file: '{reco2dur}' -- fix it by running: utils/data/get_reco2dur.sh <data-dir>\")\n    with reco2dur.open() as f:\n        for line in f:\n            recording_id, dur = line.strip().split()\n            durations[recording_id] = float(dur)\n\n    audio_set = RecordingSet.from_recordings(\n        Recording(\n            id=recording_id,\n            sources=[\n                AudioSource(\n                    type='command' if path_or_cmd.endswith('|') else 'file',\n                    channels=[0],\n                    source=path_or_cmd[:-1] if path_or_cmd.endswith('|') else path_or_cmd\n                )\n            ],\n            sampling_rate=sampling_rate,\n            num_samples=int(durations[recording_id] * sampling_rate),\n            duration=durations[recording_id]\n        )\n        for recording_id, path_or_cmd in recordings.items()\n    )\n\n    # must exist for SupervisionSet\n    segments = path / 'segments'\n    if not segments.is_file():\n        return audio_set, None\n\n    with segments.open() as f:\n        supervision_segments = [l.strip().split() for l in f]\n\n    texts = load_kaldi_text_mapping(path / 'text')\n    speakers = load_kaldi_text_mapping(path / 'utt2spk')\n    genders = load_kaldi_text_mapping(path / 'spk2gender')\n    languages = load_kaldi_text_mapping(path / 'utt2lang')\n\n    supervision_set = SupervisionSet.from_segments(\n        SupervisionSegment(\n            id=segment_id,\n            recording_id=recording_id,\n            start=float(start),\n            duration=float(end) - float(start),\n            channel=0,\n            text=texts[segment_id],\n            language=languages[segment_id],\n            speaker=speakers[segment_id],\n            gender=genders[speakers[segment_id]]\n        )\n        for segment_id, recording_id, start, end in supervision_segments\n    )\n\n    return audio_set, supervision_set\n\n\ndef load_kaldi_text_mapping(path: Path, must_exist: bool = False) -> Dict[str, Optional[str]]:\n    \"\"\"Load Kaldi files such as utt2spk, spk2gender, text, etc. as a dict.\"\"\"\n    mapping = defaultdict(lambda: None)\n    if path.is_file():\n        with path.open() as f:\n            mapping = dict(line.strip().split(' ', maxsplit=1) for line in f)\n    elif must_exist:\n        raise ValueError(f\"No such file: {path}\")\n    return mapping\n", "path": "lhotse/kaldi.py"}]}