Canardoux / flutter_sound

Flutter plugin for sound. Audio recorder and player.
Mozilla Public License 2.0
875 stars 569 forks source link

[HELP]: decibels value never goes higher than 63, even the sound is very loud #697

Open cloudseasail opened 3 years ago

cloudseasail commented 3 years ago

Wondering how the decibels value was caculated, is it reflecting the real dB value range ? (from 0 to 120dB) Actually, I never see a value larger than 63dB in my test, no matter how loud the sound is. (my kid is trying his best to yell :D)

I tried to setSubscriptionDuration from 100ms to 500ms, it make no differnce. My device is Android Mi 8. flutter_sound: ^8.1.4

mhstoller commented 3 years ago

Yes, same issue here. Additionally, on iOS it seems that idle dB level (when no sound is happening) is less than 1dB but on my android device it's close to 20dB. So, the dB range on Android is only around 44 dB in total.

I can work around this in my code by applying specific logic for each platform but it's definitely weird and would be a good fix if it's possible. It could be due to hardware differences but given that you have a completely different device than me (I'm testing with a OnePlus 6) it's more likely a software problem.

@Larpoux are there any active contributors to Tau currently?

maxkrieger commented 3 years ago

For me most of the subscription issues (including this one, and the decibels dropping to 0) disappear when I record to a file instead of a stream.

Larpoux commented 3 years ago

@Larpoux are there any active contributors to Tau currently?

You are hitting the main great τ problem. I think that this package is very good and can be potentially THE flutter plugin to do sounds.

But actually no contributors. 👎 I work myself from time to time on this project but not full time. This project cannot live without contributors. The TODO tasks are impressive and need at least one or two developers full time.

Larpoux commented 3 years ago

For me most of the subscription issues (including this one, and the decibels dropping to 0) disappear when I record to a file instead of a stream.

I am not surprised by what you are saying. Recording to file and to buffers use the Operating System Media recorder. The DB level is obtained by the OS, and is certainly correct.

When I developed recording to streams, I tried to code something to get the DB level. My code is trivial and is probably completely bad. Both on iOS and Android. Someone should master what is PCM and code correctly how to get DB level from PCM.

cloudseasail commented 3 years ago

For me most of the subscription issues (including this one, and the decibels dropping to 0) disappear when I record to a file instead of a stream.

Are you talking about record to a file and read decibels from files? Seems there is no such API availabe right now. If you mean record toFile, I am already using this in fact

void record() { _mRecorder! .startRecorder( toFile: _mPath, ) .then((value) { setState(() {}); }); _mRecorder!.onProgress!.listen((e) { print(e.decibels); _noiseLevel = e.decibels!.round().toString(); setState(() {}); }); }

Larpoux commented 3 years ago

Are you talking about record to a file and read decibels from files? Seems there is no such API availabe right now.

A long time ago, we had an issue from someone who wanted to do a static histogram of the dblevel of his/her record. Someone else posted a response that we can use FFmpeg to do that. I am not sure that his/her response was correct, but perhaps you could try to find this issue and look to it (I do not kown its number : issues are again a terrible mess).

github-actions[bot] commented 10 months ago

This issue is stale because it has been open 90 days with no activity. Leave a comment or this will be closed in 7 days.

SheepYang1993 commented 2 months ago

Is there any update progress? I used the e.decibels returned by Recorder.onProgress to draw the waveform, but the decibels seems to be inaccurate. @Larpoux

On the left are waveforms drawn by other app, and on the right are waveforms drawn by me. My waveform doesn't seem to fluctuate that much cf5352d2d990fecc4339382aa480111

flutter_sound: 9.9.2 Android13

Larpoux commented 2 months ago

Someone should master what is PCM and code correctly how to get DB level from PCM.

This remark was 3 years ago. But during these 3 years, nobody tried to work on that point. This is bad.

Larpoux commented 2 months ago

Note: if you use StartRecorderToStream, you receive the audio data in your StreamSink. You can compute yourself the db level of this stream, using the algorithm that is good for you (there are many algorithms possible. Several of them are pretty complex, and others are very simple). Perhaps some Flutter Sound users already did that and can give to you the correct code.

But of course it would be much better to insert this code inside Flutter Sound itself.

Larpoux commented 2 months ago

In may, we had a Pull Request for Flutter Web for the db recording level #1031.

Actually we have a problem because our 3 platforms (Android, iOS and Web) are never synchronized. Some features are supported better on web, others are supported better on iOS or Android. My wish is to merge android, iOS and web code inside a common code. Half of this code will be coded in dart, and the other half will be coded in rust and accessed via FFI.

This is a major dev, and I don’t expect to deliver a beta version of Flutter Sound 10.0 before next year.

SheepYang1993 commented 2 months ago

Note: if you use StartRecorderToStream, you receive the audio data in your StreamSink. You can compute yourself the db level of this stream, using the algorithm that is good for you (there are many algorithms possible. Several of them are pretty complex, and others are very simple). Perhaps some Flutter Sound users already did that and can give to you the correct code.

But of course it would be much better to insert this code inside Flutter Sound itself.

Okay, then I'll try using the data stream returned by StreamSink to calculate decibels Thanks a lot.

Larpoux commented 2 months ago

@SheepYang1993 , I expect to work on this point soon. Probably in a few weeks. If you can wait a little bit, it will be certainly better than to implement yourself this feature.

SheepYang1993 commented 2 months ago

Btw, can't startRecorder (toStreamInt16) be used now? I can't get the callback, in recorder.onProgress. but toStream can get the callback. flutter_sound: 9.9.2

@Larpoux

Larpoux commented 2 months ago

Actually, toStreamInt16 and toStreamFloat32 are only implemented on flutter web. Still not on mobiles. This is one of the many things that I have to do. This is important to support these two codecs, because it is actually the only way to work with several channels.

SheepYang1993 commented 2 months ago
    StreamController<Uint8List> recordingDataController = StreamController<Uint8List>();

    recordingDataSubscription = recordingDataController.stream.listen((Uint8List buffer) {
      sink.add(buffer);
      voiceWaveList.addAll(buffer);
    });

    await soundRecorder.startRecorder(
      toStream: recordingDataController.sink,
      codec: Codec.pcm16,
      numChannels: 1,
      sampleRate: 44100,
      bufferSize: 8192,
    );

How can I obtain Int16List ? @Larpoux

Larpoux commented 2 months ago

You can try to get the ByteBuffer of your UInt8List and then get the int16List with asInt16List(). Note : I have never tried this. Usually I loop into the UInt8List and build a Int16 from each two uint8. This is very simple. But the former way should be more efficient.

SheepYang1993 commented 2 months ago

Sorry,I just don't know how to splice two Uint8Lists into an Int16List now

I tried to splice it together like this, but the result was not correct

stream.listen((Uint8List buffer) {
      sink.add(buffer);
      tempList.add(buffer);
      if (tempList.length >= 2) {
        Int16List buffer16 = Int16List.fromList(tempList[0] + tempList[1]);
        voiceWaveList.addAll(buffer16);
        tempList.clear();
      }
    });

I can now draw the correct waveform using the following code

    final ByteData data = await rootBundle.load('assets/sound/sample.pcm');
    final Int16List bytes =
        data.buffer.asInt16List(data.offsetInBytes, data.lengthInBytes ~/ 2);
    voiceWaveList.addAll(bytes.toList());

@Larpoux

Larpoux commented 2 months ago

Yes, using the data buffer is probably better.

For your information :

    Uint8List buf = Uint8List(2 * bufferInt16.length);
    for (int i = 1; i < bufferInt16.length; ++i) {
      int v = bufferInt16[i];
      buf[2 * i + 1] = v >> 8; // Little Endian
      buf[2 * i] = v & 0xFF;
    }

And the opposite

Int16List buf = Int16List(bufferUint8List.length /2);
for (int i = 0; i < buf.length; ++ i)
{
  buf[i] = bufferUint8List[2*i+1] * 256 +  bufferUint8List[2*i]; // Little Endian
}

Note : this code is not tested and could be adjusted if necessary