Code Monkey home page Code Monkey logo

morse-decoder's Introduction

Morse Code Translator with Audio - Morse Decoder

npm-version npm-downloads

Morse code encoder and decoder with no dependencies. It supports Latin, Cyrillic, Greek, Hebrew, Arabic, Persian, Japanese, Korean, and Thai, with audio-generation functionality using the Web Audio API.

Installation

npm

$ npm install morse-decoder --save

yarn

$ yarn add morse-decoder

Usage

Common JS

const morse = require('morse-decoder');
const encoded = morse.encode('SOS'); // ... --- ...
const decoded = morse.decode('... --- ...'); // SOS
const characters = morse.characters(); // {'1': {'A': '.-', ...}, ..., '11': {'ㄱ': '.-..', ...}}
const audio = morse.audio('SOS');
audio.play(); // play audio
audio.stop(); // stop audio (cannot resume)
audio.exportWave(); // download audio wave file (promise)
const url = await audio.getWaveUrl(); // get audio wave url (promise)
const blob = await audio.getWaveBlob(); // get audio wave blob (promise)

Browser

Morse decoder exports a global object named 'morse-decoder';

const morse = window['morse-decoder']
const audioElement = document.querySelector('audio');
const helloAudio = morse.audio('Hello world');
helloAudio.getWaveUrl().then((url) => {
    document.querySelector('#morse')
    .setAttribute('src', url);
});

Options and localization

You can customize the dash, dot, or space characters and specify the alphabet with the priority option for an accurate encoding and decoding.

The priority option gives direction to the plugin to start searching for the given character set first.

Set the priority option according to the list below.

  • 1 => ASCII (Default)
  • 2 => Numbers
  • 3 => Punctuation
  • 4 => Latin Extended (Turkish, Polish etc.)
  • 5 => Cyrillic
  • 6 => Greek
  • 7 => Hebrew
  • 8 => Arabic
  • 9 => Persian
  • 10 => Japanese
  • 11 => Korean
  • 12 => Thai
const cyrillic = morse.encode('Ленинград', { priority: 5 }); // .-.. . -. .. -. --. .-. .- -..
const greek = morse.decode('... .- --. .- .--. .--', { priority: 6 }); // ΣΑΓΑΠΩ
const hebrew = morse.decode('.. ––– . –––', { dash: '–', dot: '.', priority: 7 }); // יהוה
const japanese = morse.encode('NEWS', { priority: 10, dash: '-', dot: '・', separator: ' ' }); // -・ ・ ・-- ・・・
const characters = morse.characters({ dash: '–', dot: '•' }); // {'1': {'A': '•–', ...}, ..., '11': {'ㄱ': '•–••', ...}}
const arabicAudio = morse.audio('البراق', { // generates the Morse .- .-.. -... .-. .- --.- then generates the audio from it
  wpm: 18, // sets the wpm based on the Paris method, note that setting this will override and set the unit and fwUnits accordingly
  unit: 0.1, // period of one unit, in seconds, 1.2 / c where c is speed of transmission, in words per minute
  fwUnit: 0.1, // period of one Farnsworth unit to control intercharacter and interword gaps
  volume: 100, // the volume in percent (0-100)
  oscillator: {
    type: 'sine', // sine, square, sawtooth, triangle
    frequency: 500,  // value in hertz
    onended: function () { // event that fires when the tone stops playing
      console.log('ended');
    }
  }
});
const oscillator = arabicAudio.oscillator; // OscillatorNode
const context = arabicAudio.context; // AudioContext;
const gainNode = arabicAudio.gainNode; // GainNode
arabicAudio.play(); // will start playing Morse audio
arabicAudio.stop(); // will stop playing Morse audio

Contributions

morse-decoder has been developed with extensive feedback and contributions from numerous developers. Special thanks to Chris Jones, who added many great features.

Generating Minified Files

Install node and npm and run the commands below.

$ npm install
# generate `index.js` inside `src`
$ npm run build
# generate `morse-decoder.min.js` (minified) inside `dist`
$ npm run build-rel

License

The MIT License (MIT). Please see License File for more information.

morse-decoder's People

Contributors

aimetpgm avatar chris--jones avatar drishit96 avatar mauricetmeyer avatar ozdemirburak avatar rafaelalmeidatk avatar stidges avatar zerosoul avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

morse-decoder's Issues

End of audio detection

Is there any way to detect when a morse audio has ended? What I want to do is to change the class of a button after the audio has ended. Thank you

oscillator of null

const oscillator = offlineContext.createOscillator();
                                      ^

TypeError: Cannot read property 'createOscillator' of null

I can't resolve this error, something can help me?

Can't Play the Audio More Than Once in Safari Mobile (Web Audio API)

This is a weird bug that I found recently. I have not had a chance to try it on a MacBook or an emulator, but I tried with both iOS 11 and iOS 12 in Safari Mobile and I still could not figure it out.

If you click to the Play button, not only you may not stop it from playing, but also you may not make it play more than once.

You can find an example and test it out on JSFiddle.

Note: There are many Stack Overflow issues like this for reference.

Example Issue 1
Example Issue 2

Failed to execute 'stop' on 'AudioScheduledSourceNode': cannot call stop without calling start first.

Hi @ozdemirburak
When i am clicking first time on the playicon then the audio has been start playing but as soon as i am clicking again to pause the audio it showing me this error "Failed to execute 'stop' on 'AudioScheduledSourceNode': cannot call stop without calling start first."

I am unable to understand what i am making wrong. Please help some one.

const morse = require('morse-decoder');
const togglePlay = (event) => {
      const audio = morse.audio('My Text');
      if (event.target.className === 'playicon') {
          audio.play();
          event.target.className = 'pauseicon';
      } else {
          audio.stop();
          event.target.className = 'playicon';
      }
  }

<div className="playicon" onClick={togglePlay}></div>

Export Morse Code Audio to WAV

Currently, the library misses a feature that is a bit challenging: exporting the Morse code audio to WAV.

Not sure how to do this effectively, but the gist below clearly shows how to create WAV from the buffer, which may help in the beginning.

Link to the Gist

Error

TypeError: Cannot read property 'createOscillator' of null
at Object.audio in morsify/src/morsify.js — line 192

Modify Options - Add WPM and Volume Parameters

Currently, there are two variables that control the sound - unit and fwUnit. And these confuse most users about the Audio generated.

Instead of these two, taking PARIS (50 units) as the standard word (60 seconds / 50 units = 1.2), a WPM parameter for an end user would be better.

Here is a great resource on this: https://www.morsecodeclassnet.com/ch3-timing/

Other than this, the current default frequency value is 500, but a more common value would be better.

Lastly, a volume parameter can also be added.

Here is the expected output:

 const options: Options = {
    ...opts,
    dash: opts.dash || '-',
    dot: opts.dot || '.',
    space: opts.space || '/',
    separator: opts.separator || ' ',
    invalid: opts.invalid || '#',
    priority: opts.priority || 1,
    >>>>>>>wpm: opts.wpm || 20,
    >>>>>>>volume: opts.volume || 100,
    oscillator: {
      ...opts.oscillator,
      type: opts.oscillator?.type || 'sine', // sine, square, sawtooth, triangle
       >>>>>>>frequency: opts.oscillator?.frequency || SOME_ANOTHER_VALUE, // value in hertz
      onended: opts.oscillator?.onended || null // event that fires when the tone has stopped playing
    }
  };

Proposed API updates to audio functions

Although there's a decent workaround to being able to seek, pause and stop the audio by binding the wave to an audio control (see #25 (comment)), the underlying API is a little confusing and/or lacking in function:

  • Calling stop() effectively causes disposal of the audio source, meaning subsequent plays do not work without re-creating the audio
  • There is no in-built way to seek or pause the audio
  • There is no in-built way to retrieve information about the audio playback such as currentTime and totalTime

All of these items make it difficult to build a complete UI to interface with the library.

Proposed solution

  1. I see no reason why we couldn't just re-render the audio if necessary when someone hits play again. Their intent is obvious, and the audio becoming unplayable after stop is not obvious.

  2. The use of the offline audio context makes it possible to keep the audio buffer in memory and re-use it!
    This has the downside though of potentially keeping a large audio buffer around though, so this could be an optimisation option.
    e.g. perhaps stop could take in a boolean parameter that indicates if the buffer should be disposed - stop(true) and otherwise you could call audio.dispose() to remove the buffer.

  3. Add seek (or setCurrentTime()) to allow playback from any point in the audio, pause would act the same as stop except that it would not reset the currentTime to 0, so a subsequent play would resume from that point.

  4. Expose getCurrentTime() and getTotalTime() on the audio object. These would be functions because it might be expensive/unnecessary to poll and update a current time property; getTotalTime would need to wait until rendering had completed (although you could get the total duration time before even playing the audio)

  5. One gotcha with having re-playable/pausable audio is the onended event as this will now be triggered every time the playback stops (even on pause); we could simply rename this event to onstopped and include the current time in the event object (so you could see if it was paused or completed), or make onended only trigger at the end of the audio or when disposed. It might also be useful to know when the audio has finished rendering - onready, and we could re-work the API to allow synchronous usage via this callback if that seems useful.

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.