Fail to cast Audio feature for numpy arrays in datasets 4.0.0
Opened by luatil-cloud (closed)

### Describe the bug

Casting features with Audio for numpy arrays - done here with `ds.map(gen_sine, features=features)` fails
in version 4.0.0 but not in version 3.6.0


### Steps to reproduce the bug

The following `uv script` should be able to reproduce the bug in version 4.0.0
and pass in version 3.6.0 on a macOS Sequoia 15.5

```python
# /// script
# requires-python = ">=3.13"
# dependencies = [
#   "datasets[audio]==4.0.0",
#   "librosa>=0.11.0",
# ]
# ///
# NAME
#   create_audio_dataset.py - create an audio dataset of sine waves
#
# SYNOPSIS
#   uv run create_audio_dataset.py
#
# DESCRIPTION
#   Create an audio dataset using the Hugging Face [datasets] library.
#   Illustrates how to create synthetic audio datasets using the [map]
#   datasets function.
#
#   The strategy is to first create a dataset with the input to the
#   generation function, then execute the map function that generates
#   the result, and finally cast the final features.
#
# BUG
#   Casting features with Audio for numpy arrays -
#   done here with `ds.map(gen_sine, features=features)` fails
#   in version 4.0.0 but not in version 3.6.0
#
#   This happens both in cases where --extra audio is provided and where is not.
#   When audio is not provided i've installed the latest compatible version
#   of soundfile.
#
#   The error when soundfile is installed but the audio --extra is not
#   indicates that the array values do not have the `.T` property,
#   whilst also indicating that the value is a list instead of a numpy array.
#
#   Last lines of error report when for datasets + soundfile case
#   ...
#
#      File "/Users/luasantilli/.cache/uv/archive-v0/tc_5IhQe7Zpw8ZXgQWpnl/lib/python3.13/site-packages/datasets/features/audio.py", line 239, in cast_storage
#          storage = pa.array([Audio().encode_example(x) if x is not None else None for x in storage.to_pylist()])
#                              ~~~~~~~~~~~~~~~~~~~~~~^^^
#        File "/Users/luasantilli/.cache/uv/archive-v0/tc_5IhQe7Zpw8ZXgQWpnl/lib/python3.13/site-packages/datasets/features/audio.py", line 122, in encode_example
#          sf.write(buffer, value["array"].T, value["sampling_rate"], format="wav")
#                           ^^^^^^^^^^^^^^^^
#      AttributeError: 'list' object has no attribute 'T'
#   ...
#
#   For the case of datasets[audio] without explicit adding soundfile I get an FFmpeg
#   error.
#
#   Last lines of error report:
#
#   ...
#     RuntimeError: Could not load libtorchcodec. Likely causes:
#               1. FFmpeg is not properly installed in your environment. We support
#                  versions 4, 5, 6 and 7.
#               2. The PyTorch version (2.7.1) is not compatible with
#                  this version of TorchCodec. Refer to the version compatibility
#                  table:
#                  https://github.com/pytorch/torchcodec?tab=readme-ov-file#installing-torchcodec.
#               3. Another runtime dependency; see exceptions below.
#             The following exceptions were raised as we tried to load libtorchcodec:
#
#     [start of libtorchcodec loading traceback]
#     FFmpeg version 7: dlopen(/Users/luasantilli/.cache/uv/archive-v0/RK3IAlGfiICwDkHm2guLC/lib/python3.13/site-packages/torchcodec/libtorchcodec_decoder7.dylib, 0x0006): Library not loaded: @rpath/libavutil.59.dylib
#       Referenced from: <6DB21246-F28A-31A6-910A-D8F3355D1064> /Users/luasantilli/.cache/uv/archive-v0/RK3IAlGfiICwDkHm2guLC/lib/python3.13/site-packages/torchcodec/libtorchcodec_decoder7.dylib
#       Reason: no LC_RPATH's found
#     FFmpeg version 6: dlopen(/Users/luasantilli/.cache/uv/archive-v0/RK3IAlGfiICwDkHm2guLC/lib/python3.13/site-packages/torchcodec/libtorchcodec_decoder6.dylib, 0x0006): Library not loaded: @rpath/libavutil.58.dylib
#       Referenced from: <BD3B44FC-E14B-3ABF-800F-BB54B6CCA3B1> /Users/luasantilli/.cache/uv/archive-v0/RK3IAlGfiICwDkHm2guLC/lib/python3.13/site-packages/torchcodec/libtorchcodec_decoder6.dylib
#       Reason: no LC_RPATH's found
#     FFmpeg version 5: dlopen(/Users/luasantilli/.cache/uv/archive-v0/RK3IAlGfiICwDkHm2guLC/lib/python3.13/site-packages/torchcodec/libtorchcodec_decoder5.dylib, 0x0006): Library not loaded: @rpath/libavutil.57.dylib
#       Referenced from: <F06EBF8A-238C-3A96-BFBB-B34E0BBDABF0> /Users/luasantilli/.cache/uv/archive-v0/RK3IAlGfiICwDkHm2guLC/lib/python3.13/site-packages/torchcodec/libtorchcodec_decoder5.dylib
#       Reason: no LC_RPATH's found
#     FFmpeg version 4: dlopen(/Users/luasantilli/.cache/uv/archive-v0/RK3IAlGfiICwDkHm2guLC/lib/python3.13/site-packages/torchcodec/libtorchcodec_decoder4.dylib, 0x0006): Library not loaded: @rpath/libavutil.56.dylib
#       Referenced from: <6E59F017-C703-3AF6-A271-6277DD5F8170> /Users/luasantilli/.cache/uv/archive-v0/RK3IAlGfiICwDkHm2guLC/lib/python3.13/site-packages/torchcodec/libtorchcodec_decoder4.dylib
#       Reason: no LC_RPATH's found
#   ...
#
#   This is strange because the the same error does not happen when using version 3.6.0 with datasets[audio].
#
#   The same error appears in python3.12
## Imports
import numpy as np
from datasets import Dataset, Features, Audio, Value

## Parameters
NUM_WAVES = 128
SAMPLE_RATE = 16_000
DURATION = 1.0

## Input dataset arguments
freqs = np.linspace(100, 2000, NUM_WAVES).tolist()
ds = Dataset.from_dict({"frequency": freqs})

## Features for the final dataset
features = Features(
    {"frequency": Value("float32"), "audio": Audio(sampling_rate=SAMPLE_RATE)}
)


## Generate audio sine waves and cast features
def gen_sine(example):
    t = np.linspace(0, DURATION, int(SAMPLE_RATE * DURATION), endpoint=False)
    wav = np.sin(2 * np.pi * example["frequency"] * t)
    return {
        "frequency": example["frequency"],
        "audio": {"array": wav, "sampling_rate": SAMPLE_RATE},
    }


ds = ds.map(gen_sine, features=features)

print(ds)
print(ds.features)
```

### Expected behavior

I expect the result of version `4.0.0` to be the same of that in version `3.6.0`. Switching the value
of the script above to `3.6.0` I get the following, expected, result: 

```
$ uv run bug_report.py
Map: 100%|███████████████████████████████████████████████████████| 128/128 [00:00<00:00, 204.58 examples/s]
Dataset({
    features: ['frequency', 'audio'],
    num_rows: 128
})
{'frequency': Value(dtype='float32', id=None), 'audio': Audio(sampling_rate=16000, mono=True, decode=True, id=None)}
```

### Environment info

- `datasets` version: 4.0.0
- Platform: macOS-15.5-arm64-arm-64bit-Mach-O
- Python version: 3.13.1
- `huggingface_hub` version: 0.33.4
- PyArrow version: 20.0.0
- Pandas version: 2.3.1
- `fsspec` version: 2025.3.0

Comments:
thanks for reporting, I opened a PR and I'll make a patch release soon 

> thanks for reporting, I opened a PR and I'll make a patch release soon

Thank you very much @lhoestq!