Giter Club home page Giter Club logo

wavesurfer-blazor-wrapper's People

Stargazers

 avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

wavesurfer-blazor-wrapper's Issues

update to .net 7 , and region content

Hello, this is great/awesome, I picked this over howler ๐Ÿฅ‡ , can you please update to core 7, also I noticed you have separate timeline and regions for content.

I have a list of songs for an online album, where we want to sing karaoke, but when I am trying to do lyrics (expand on hover, based on timestamp, and its confusing since it sits across two or three wavesurfer plugins (regions, timeline2, hover), but my data sits in the same C# song models, not sure how to do both timestamp, lyrics synced with the displayed time stamp on hover, while displaying play rewind and custom buttons like share.

  • Since both timestamps and text, are "content"... can we load both in the wrapper.
  • Would it be possible to use this wrapper in asp MVC core views?
  • in the docs, whats the difference between regions params, and regions options?

thanks.

OnFinish Exception

When audio is playing and reaches the end, an exception is thrown: Uncaught (in promise) Error: System.ArgumentException: The type 'WavesurferPlayer' does not contain a public invokable method with [JSInvokableAttribute("OnWavesurferFinish")].

This exception appears to trigger from wavesurfer-user.js line 63. The JS interop is calling back to the "OnWavesurferPause" invokable method, but there is no method in WavesurferPlayer.razor that has [JSInvokable("OnWavesurferFinish")] attached to it, which calls the OnFinish EventCallback.

I think just adding this to WavesurferPlayer.razor would possibly work:

[JSInvokable]
public async Task OnWavesurferFinish()
{
    await OnFinish.InvokeAsync();
}

I could add this if you want. If that's ok with you, how would you prefer that be done? I could create a branch, add the changes and make a PR. Let me know if that's helpful or if you'd rather look into this on your own. Thank you!

Feature Request: Regions Support

I was wondering if support for adding regions could be implemented. Wavesurfer.js has a few methods in the regions plugin that are not present on this wrapper. https://wavesurfer-js.org/plugins/regions.html

Specifically, there's no way to add or clear regions. There are callbacks implemented for when regions are added and changed, but no direct methods on the object that allow you to add regions.

My specific use-case would be something like this:

<WavesurferPlayer @ref="this.audioPlayer" />

@code{
    private WavesurferPlayer? audioPlayer;

    private async Task OnButtonClick()
    {
        await this.audioPlayer?.AddRegion(
            id: "region1",
            start: 3f,
            end: 6f,
            loop: false,
            drag: false,
            resize: false,
            color: "rgba(1, 0.5, 0.5, 1)",
            minLength: 3f,
            maxLength: 6f);
    }
}

Let me know if I can help with implementing this or if this functionality already exists and I'm just missing it. Thanks!

help getting Peaks in Json format

Hi can you please help me with trying to get Peaks in a json format please. I have the below code in javascript I just need it to work in c#

<script type="text/javascript" src="js/jquery-3.6.0.min.js"></script>
    <script type="text/javascript" src="https://unpkg.com/wavesurfer.js"></script>
    <script type="text/javascript">

        jQuery(document).ready(function($){

            "use strict"

            var dataArr = [],
            processArr = [],
            len, 
            counter,
            peakType = 'pcm',
            exportData,
            loader = $('#loader'),
            output = $('#output'),
            exportLink = $('#exportLink'),
            pcmLength,
            pcmAccuracy,
            waveform = $('#waveform'),
            imageCreateCheck,
            wavesurfer

            $('input[name=peakType]').on('change',function() {
                if(this.checked){
                    peakType = this.value;
                }

                $('.waveform-data-field').hide()

                if(peakType == 'pcm'){
                    $('.waveform-data-field').show()
                }

            }).change();

            function createWs(){
                console.log('createWs')

                if(wavesurfer){
                    wavesurfer.empty();
                    wavesurfer.cancelAjax();
                    wavesurfer.destroy()
                }

                wavesurfer = WaveSurfer.create({
                    container: waveform[0],
                    backend: 'MediaElement',/*!important*/
                });

                wavesurfer.on('waveform-ready', function() {
                    console.log('waveform-ready')
                    
                    if(peakType == 'pcm'){

                        var pcm = wavesurfer.exportPCM(pcmLength, pcmAccuracy, true);

                        pcm.then(function(val) { 

                            if(Array.isArray(val)){
                                val = val.toString(); 
                            }else{
                                if(val.charAt(0) == '[')val = val.substr(1); 
                                if(val.charAt(val.length-1) == ']')val = val.substr(0, val.length-1); 
                            }

                            if(peakType == 'pcm'){
                            
                                output.append('<br>Done creating peak: ' + dataArr[counter].peakName);

                                exportData.push({name: dataArr[counter].peakName, pcm: val})
                                
                                getPeaks();

                            }else if(peakType == 'peak'){

                                writePeaks(val, dataArr[counter].peakName);

                            }

                        })

                    }
                           
                });

            }

            var audio_input = $("#audio_input").change(function(e) {

                pcmLength = $('#waveform-length').val() || 100
                pcmAccuracy = $('#waveform-accuracy').val() || 100

                createWs()

                audio_input.prop('disabled',true);
                loader.show();
                output.show().html('');
                exportLink.hide();
                exportData = [];

                dataArr = [];
                len = this.files.length;
                var i, fn;

                for(i=0; i < len; i++){
                    fn = this.files[i].name;
                    //fn = fn.substr(0,fn.lastIndexOf('.'))
                    processArr.push({file:this.files[i], peakName: fn});
                }

                getFiles();

            });

            function getFiles() {

                var data = processArr.shift();

                var title; 

                var fileReader = new FileReader();
                fileReader.onload = function(e){

                    dataArr.push(data);
                    dataArr[dataArr.length-1].url = e.target.result;

                    if(processArr.length){
                        getFiles();
                    }else{
                        output.append('Done reading all file inputs<br>Started peak creation<br>');
                        counter = -1; 
                        len = dataArr.length;
                        getPeaks(); 
                    }
      
                } 
                fileReader.onerror = function(e){
                    console.log("fileReader failed", e.name + ": " + e.message);

                    if(processArr.length){
                        getFiles();
                    }else{
                        output.append('Done reading all file inputs<br>Started peak creation<br>');
                        counter = -1; 
                        len = dataArr.length;
                        getPeaks(); 
                    }   
                }                 

                fileReader.readAsDataURL(data.file);
              
            }

            function getPeaks() {

                counter++;

                if(counter == len){
                    output.append('<br><br>Done creating all peaks!');
                    dataArr = null;
                    loader.hide();
                    audio_input.prop('disabled', false);

                    if(peakType == 'pcm'){

                        //Get the file contents
                         var txtFile = "test.txt";
                         var file = new File([""], txtFile);
                         var str = JSON.stringify(exportData, null, " ");

                         //Save the file contents as a DataURI
                         var dataUri = 'data:application/json;charset=utf-8,'+ encodeURIComponent(str);

                         var date = new Date().toLocaleString(),
                          file_name = 'peaks-' + date

                          exportLink.attr('download', file_name)


                         //Write it as the href for the link
                         exportLink.attr('href', dataUri).show();

                    }

                    audio_input.val('')

                }else{

                    wavesurfer.empty();

                    var url = dataArr[counter].url

                    if(window.location.protocol == 'https:'){
                        var wurl = url.replace('http://','https://');
                    }else{
                        var wurl = url.replace('https://','http://');
                    }

                    wavesurfer.load(wurl);

                }
            }
           
        });

        function isEmpty(str) {
            return str.replace(/^\s+|\s+$/g, '').length == 0;
        }

    </script>

Initializing multiple WavesurferPlayer instances will cause the waveform to not be displayed

If we use multiple Wavesurfer Players on a page, only the last Wavesurfer Player will work properly.
for example:

<WavesurferPlayer ShowDefaultToolbar Url="/file/corp/eXun10005/rec/20231024/1698107752864.mp3"></WavesurferPlayer>
<WavesurferPlayer ShowDefaultToolbar Url="/file/corp/eXun10005/rec/20231024/1698110477390.mp3"></WavesurferPlayer>
<WavesurferPlayer ShowDefaultToolbar Url="/file/corp/eXun10005/rec/20231024/1698108695731.mp3"></WavesurferPlayer>

image

When using the WavesurferPlayer component in multiple Razor pages, the same phenomenon occurs: only the last loaded WavesurferPlayer can display normally.

OnVolume Exception

Hey, thanks for making this wrapper. I ran into an issue trying to use the OnVolume parameter on the WavesurferPlayer component. It throws an exception:

Uncaught (in promise) Error: System.Text.Json.JsonException: The JSON value could not be converted to System.Int32. Path: $ | LineNumber: 0 | BytePositionInLine: 3.
 ---> System.FormatException: Either the JSON value is not in a supported format, or is out of bounds for an Int32.
   at System.Text.Json.Utf8JsonReader.GetInt32()
   at System.Text.Json.Serialization.Converters.Int32Converter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverter`1[[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, Int32& value)
   at System.Text.Json.Serialization.JsonConverter`1[[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   --- End of inner exception stack trace ---
   at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& state, Utf8JsonReader& reader, Exception ex)
   at System.Text.Json.Serialization.JsonConverter`1[[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.Serialization.JsonConverter`1[[System.Int32, System.Private.CoreLib, Version=6.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].ReadCoreAsObject(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.ReadCore[Object](JsonConverter jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   at System.Text.Json.JsonSerializer.Read[Object](Utf8JsonReader& reader, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Deserialize(Utf8JsonReader& reader, Type returnType, JsonSerializerOptions options)
   at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.ParseArguments(JSRuntime jsRuntime, String methodIdentifier, String arguments, Type[] parameterTypes)
   at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.InvokeSynchronously(JSRuntime jsRuntime, DotNetInvocationInfo& callInfo, IDotNetObjectReference objectReference, String argsJson)
   at Microsoft.JSInterop.Infrastructure.DotNetDispatcher.BeginInvokeDotNet(JSRuntime jsRuntime, DotNetInvocationInfo invocationInfo, String argsJson)

I think it's throwing this because the volume is supposed to be a float type, but the OnVolume parameter is EventCallback<int>. I think the JS interop is having an issue when calling back to C# with the value. This is just my suspicion.

This should be a minimal reproduction. Due to CORS issues, I don't have a URL to use in the URL parameter so you'll need your own.

<WavesurferPlayer @ref="this.audioPlayer"
                      Url="PUT YOUR AUDIO FILE HERE"
                      OnVolume="this.OnVolumeChanged"/>
<button @onclick="SetVolume">Change Volume</button>

@code{

    private WavesurferPlayer? audioPlayer = null;

    private void OnVolumeChanged(int newVol)
    {
        Console.WriteLine($"New volume = {newVol}");
    }
    private async Task SetVolume()
    {
        if (this.audioPlayer != null)
        {
            Random rand = new();
            await this.audioPlayer.SetVolume(rand.NextSingle());
        }
    }
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.