Repository: librosa/librosa

Issue:
`librosa.load` returns wrongly-typed int object
**Describe the bug**
`librosa.load` returns `int` object instead of `float`.  

**To Reproduce**
```python
import librosa

import librosa
wave, sr = librosa.load("test.wav", sr=None, mono=True)
print(type(sr))
# <class 'int'>
```

**Expected behavior**
Typing of `.load` says that it returns `float`.  
https://github.com/librosa/librosa/blob/09e4a622456bbad314e2e6d5c75879f56d728b9b/librosa/core/audio.py#L66C1-L66C31  
So, the function should return `float` object.  

**Software versions**
```
Linux-5.15.109+-x86_64-with-glibc2.35
Python 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0]
NumPy 1.23.5
SciPy 1.10.1
librosa 0.10.1
INSTALLED VERSIONS
------------------
python: 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0]

librosa: 0.10.1

audioread: 3.0.0
numpy: 1.23.5
scipy: 1.10.1
sklearn: 1.2.2
joblib: 1.3.2
decorator: 4.4.2
numba: 0.56.4
soundfile: 0.12.1
pooch: v1.7.0
soxr: 0.3.6
typing_extensions: installed, no version number available
lazy_loader: installed, no version number available
msgpack: 1.0.5

numpydoc: None
sphinx: 5.0.2
sphinx_rtd_theme: None
matplotlib: 3.7.1
sphinx_multiversion: None
sphinx_gallery: None
mir_eval: None
ipython: None
sphinxcontrib.rsvgconverter: None
pytest: 7.4.0
pytest_mpl: None
pytest_cov: None
samplerate: None
resampy: None
presets: None
packaging: 23.1```



Discussion:
Thanks for catching this!  It's a rather subtle thing, as the value and type of sr will depend on which codec path is taken (audioread vs soundfile), which resampling backend is used, etc.

However, there are a couple of things that should be fixed here:

1. the default `sr` has value 22050 (int) and type `Optional[float]`.  We should make this `22050.0`.
2. We should explicitly cast `sr` to float on return.

These are pretty easy fixes, and I don't anticipate any downstream effects.
> I don't anticipate any downstream effects.  

I have some concern.  
I notice this bug when I use `float` specific method (`float.is_integer()`).  
Integer also have `int`-specific methods ([method list](https://docs.python.org/3/library/stdtypes.html#additional-methods-on-integer-types)).  
Semantically this is subtle thing, but practically this could have some downstream effects (of course, very minor case).  

I totally agree with your bug-fix plan, but we should emphasis ***backward-incompatibility*** notice in release note / change log.  

Ah, to clarify, I meant unintended consequences for the rest of the library, not for downstream code.
Oh, I misunderstanded it, now I got it.  

Can I make a pull request with your bug-fix plan?
Sure, thanks!

Resolving patch:
diff --git a/librosa/core/audio.py b/librosa/core/audio.py
--- a/librosa/core/audio.py
+++ b/librosa/core/audio.py
@@ -63,7 +63,7 @@ def load(
     duration: Optional[float] = None,
     dtype: DTypeLike = np.float32,
     res_type: str = "soxr_hq",
-) -> Tuple[np.ndarray, float]:
+) -> Tuple[np.ndarray, Union[int, float]]:
     """Load an audio file as a floating point time series.
 
     Audio will be automatically resampled to the given rate
diff --git a/librosa/core/convert.py b/librosa/core/convert.py
--- a/librosa/core/convert.py
+++ b/librosa/core/convert.py
@@ -600,14 +600,14 @@ def blocks_to_samples(
 
 @overload
 def blocks_to_time(
-    blocks: _IntLike_co, *, block_length: int, hop_length: int, sr: int
+    blocks: _IntLike_co, *, block_length: int, hop_length: int, sr: float
 ) -> np.floating[Any]:
     ...
 
 
 @overload
 def blocks_to_time(
-    blocks: _SequenceLike[_IntLike_co], *, block_length: int, hop_length: int, sr: int
+    blocks: _SequenceLike[_IntLike_co], *, block_length: int, hop_length: int, sr: float
 ) -> np.ndarray:
     ...
 
@@ -618,7 +618,7 @@ def blocks_to_time(
     *,
     block_length: int,
     hop_length: int,
-    sr: int,
+    sr: float,
 ) -> Union[np.floating[Any], np.ndarray]:
     ...
 
@@ -628,7 +628,7 @@ def blocks_to_time(
     *,
     block_length: int,
     hop_length: int,
-    sr: int,
+    sr: float,
 ) -> Union[np.floating[Any], np.ndarray]:
     """Convert block indices to time (in seconds)
 


Test patch: