Command line decoder for NRSC5 (aka HD Radio here in the US) now available for SDRplay RSPs (2024)

Likes

" ); } else { wrap = '

Attachments:

    '; count = 0; for (i = 0; i < response.length; i++) { if (response[i].Inline == false) { wrap += '
  • ' + response[i].Name + ' (' + response[i].HumanSize + ')
  • "; count++; } } wrap += '

'; if (count > 0) { $('#attachments' + id).replaceWith(wrap); } else { $('#attachments' + id).replaceWith( "

" ); } } }); } var modTimeoutId; function modOnFormChange(id, draftid, groupurl, csrf) { clearTimeout(modTimeoutId); if (modSaving == true) { modTimeoutId = setTimeout(function () { // Runs 1 second (1000 ms) after the last change modOnFormChange(id, draftid, groupurl, csrf); }, 1000); return; } modTimeoutId = setTimeout(function () { // Runs 1 second (1000 ms) after the last change modSaveDraft(id, draftid, groupurl, csrf, false); }, 1000); } var modSaving = false; // modSaveDraft saves the current form state in the draft. function modSaveDraft(id, draftid, groupurl, csrf, onLeave) { if (draftid == 0) { console.log("DraftID 0, not modSaving"); return; } console.log("DELETEDDRAFT IS:", modDeletedDraft); console.log("DESTROYEDEDITOR IS:", modDestroyedEditor); if (modDeletedDraft == true) { console.log('NOT SAVING BECAUSE OF DELETED'); return; } if (modDestroyedEditor == true) { console.log('NOT SAVING BECAUSE OF DESTROYED'); return; } modSaving = true; console.log('modSaving'); var fromval = $('#from' + id).val(); var subject = $('#subject' + id).val(); var body = $('#editor' + id).val(); var bodytype = $('#bodytype' + id).val(); var replyto = $('#replyto' + id).val(); var special = '0'; if ($('#special').prop('checked') == true) { special = '1'; } var bccme = '0'; if ($('#bccmecheck' + id).prop('checked') == true) { bccme = '1'; } var bccall = '0'; if ($('#bccall' + id).prop('checked') == true) { bccall = '1'; } var saveval = '1'; if (onLeave == true) { saveval = '2'; } var hashtags = $('#hashtags').val(); upload = { draftid: draftid, csrf: csrf, from: fromval, subject: subject, body: body, bodytype: bodytype, special: special, replyto: replyto, bccme: bccme, bccall: bccall, hashtags: JSON.stringify(hashtags), mid: id, save: saveval }; let opts = { url: groupurl + '/draftop', cache: false, data: upload, method: 'POST', xhrFields: { withCredentials: true }, dataType: 'json' }; if (modUnloading == false) { // if we are unloading we don't want to retry, because sometimes // that can result in a spurious error, esp on Firefox opts.retryCount = 5; opts.retryVerify = modRetryVerify; } $.ajax(opts).done(function (response) { // Do something with the request console.log('saved'); modSaving = false; }); } // called to see if we need to continue retrying function modRetryVerify() { if (modDeletedDraft == true || modDestroyedEditor == true) { return false; } return true; } // stop modSaving drafts when we do a submit var postVar = null; // Code to find and return a selected piece of HTML. function modGetSelection(id) { var flag = 0; var sel = document.getSelection(); var selText = ''; id = 'msgbody' + id; var forkfork = document.getElementById(id); if (sel.rangeCount > 0) { var range = sel.getRangeAt(0); var test = range.cloneContents(); var clonedSelection = ''; if (typeof test.getElementByID != 'undefined') { clonedSelection = range.cloneContents().getElementById(id); } if (clonedSelection) { selText = clonedSelection.innerHTML; } else { clonedSelection = range.cloneContents(); var startNode = sel.getRangeAt(0).startContainer.parentNode; //console.log(modIsChild(startNode, forkfork)); if (modIsChild(startNode, forkfork)) { var div = document.createElement('div'); div.appendChild(clonedSelection); selText = div.innerHTML; } } } return selText.toString(); } function modIsChild(child, parent) { if (child === parent) return true; var current = child; while (current) { if (current === parent) return true; current = current.parentNode; } return false; } return { InitEditor: function ( id, bodyType, draftid, groupurl, csrf, handleAttachments, noFontChanges, isReply, isWiki, body, sig, onInitFunc ) { if (typeof onInitFunc === 'undefined') { onInitFunc = null; } document.body.addEventListener('htmx:beforeSwap', modDestroyAllEditors, {once: true}); modDeletedDraft = false; modDestroyedEditor = false; modUnloading = false; $('#preview' + id).hide(); $('#addattachments' + id).hide(); $('#return' + id).hide(); $('#markdownlink' + id).hide(); if (bodyType == 'html') { if (sig != '') { $('#editor' + id).val(sig); //tinyMCE.get('editor'+id).setContent(sig); } editor.initHTMLEditor( id, draftid, groupurl, csrf, handleAttachments, noFontChanges, isReply, isWiki, body, sig, onInitFunc ); } else { if (sig != '') { $('#editor' + id).val(sig); } editor.initPlainEditor(id, bodyType, groupurl, handleAttachments, sig); } }, initHTMLEditor: function ( id, draftid, groupurl, csrf, handleAttachments, noFontChanges, isReply, isWiki, body, sig, onInitFunc ) { if (typeof onInitFunc === 'undefined') { onInitFunc = null; } // extras: print, emoticons, image, insert, media, print /* All plugins: 'advlist autolink lists link image print preview hr anchor pagebreak', 'searchreplace wordcount visualblocks visualchars code fullscreen', 'insertdatetime media nonbreaking save table contextmenu directionality', 'emoticons template paste textcolor colorpicker textpattern imagetools codesample toc' */ modDeletedDraft = false; modDestroyedEditor = false; modUnloading = false; let attachments = ''; if (handleAttachments == 0 || handleAttachments == 3) { attachments = ' addPictures addAttachments'; } let fontchanges = ''; if (noFontChanges == false) { fontchanges = ' fontselect fontsizeselect forecolor backcolor'; } let fontawesome = ' charmap'; let forceRootBlock = false; if (isWiki == true) { attachments += ' addWikiImage addWikiLink addWikiTOC'; fontawesome = ' fontawesome'; // BORK fontawesome = ''; forceRootBlock = 'p'; } let toolbar1 = 'styleselect bold italic bullist numlist link blockquote alignleft aligncenter alignright' + attachments + ' advancedToolbar'; let toolbar2 = 'strikethrough underline hr alignjustify' + fontchanges + ' removeformat' + fontawesome + ' outdent indent undo redo preview code'; let small_toolbar1 = 'bold italic link blockquote' + attachments + ' advancedToolbar'; let small_toolbar2 = 'strikethrough underline hr alignjustify removeformat outdent indent'; let tm_fonts = 'Arial=arial,helvetica,sans-serif;' + 'Arial Black=arial black,avant garde;' + 'Comic Sans MS=comic sans ms;' + 'Courier Neue=courier_newregular,courier;' + 'Helvetica Neue=helvetica neue;' + 'Helvetica=helvetica;' + 'Impact=impactregular,chicago;' + 'Lucida Grande=lucida grande;' + 'Tahoma=tahoma,arial,helvetica,sans-serif;' + 'Times New Roman=times new roman,times;' + 'Verdana=verdana,geneva'; let plugins = [ 'SplitBlockquote', 'advlist autolink lists link image preview hr anchor', 'code fullscreen', 'nonbreaking table charmap', 'textcolor colorpicker imagetools noneditable' ]; let css = '/bootstrap/3.3.6/css/bootstrap.min.css,/bootstrap/3.3.6/css/bootstrap-theme.min.css,/css/groupsio.css,/css/tinymce.css,/fontawesome/all.min.css'; let fontsizes = '8pt 10pt 11pt 12pt 14pt 18pt 24pt 36pt'; let codesample_languages = [ { text: 'C', value: 'c' }, { text: 'C#', value: 'csharp' }, { text: 'C++', value: 'cpp' }, { text: 'CSS', value: 'css' }, { text: 'Go', value: 'go' }, { text: 'HTML/XML', value: 'markup' }, { text: 'Java', value: 'java' }, { text: 'JavaScript', value: 'javascript' }, { text: 'PHP', value: 'php' }, { text: 'Python', value: 'python' }, { text: 'Ruby', value: 'ruby' } ]; let style_formats = [ { title: 'Paragraph', block: 'p' }, { title: 'Header 1', block: 'h1' }, { title: 'Header 2', block: 'h2' }, { title: 'Header 3', block: 'h3' }, { title: 'Header 4', block: 'h4' }, { title: 'Header 5', block: 'h5' }, { title: 'Header 6', block: 'h6' } ]; if (isReply == true) { toolbar1 = 'quoteMessage ' + toolbar1; small_toolbar1 = 'quoteMessage ' + small_toolbar1; } if (document.documentElement.clientWidth > 1000) { tinymce.init({ noneditable_noneditable_class: 'fa', extended_valid_elements: 'span[*]', branding: false, link_context_toolbar: true, default_link_target: '_blank', link_assume_external_targets: true, elementpath: false, forced_root_block: forceRootBlock, content_css: css, relative_urls: false, remove_script_host: false, menubar: false, statusbar: true, plugins: plugins, toolbar1: toolbar1, toolbar2: toolbar2, font_formats: tm_fonts, browser_spellcheck: true, contextmenu: false, selector: '#editor' + id, resize: true, fontsize_formats: fontsizes, style_formats: style_formats, setup: function (teditor) { teditor.on('Init', function (e) { // see if any text is selected toquote = modGetSelection(id); if (toquote != '') { console.log('id=' + id); editor.ShowMessageHistory(id, groupurl, 'html', toquote, sig, true); } else { if (body != "") { console.log("body setContent"); teditor.setContent(body); } else if (sig != "") { console.log("sig setContent " + sig); teditor.setContent(sig); } } if (onInitFunc != null) { onInitFunc(e); } }); teditor.on('BeforeRenderUI', function (e) { teditor.theme.panel .find('toolbar') .slice(1) .hide(); }); teditor.addButton('advancedToolbar', { tooltip: 'Show advanced toolbar', icon: 'fa fa-bars', onclick: function () { if (!this.active()) { this.active(true); teditor.theme.panel .find('toolbar') .slice(1) .show(); } else { this.active(false); teditor.theme.panel .find('toolbar') .slice(1) .hide(); } } }); teditor.addButton('addPictures', { tooltip: 'Add pictures', icon: 'fa fa-image', onclick: function () { modUploaderPrompt("pictures", id, draftid, groupurl, csrf); } }); teditor.addButton('addAttachments', { tooltip: 'Add attachments', icon: 'fa fa-paperclip', onclick: function () { modUploaderPrompt("attachments", id, draftid, groupurl, csrf); } }); if (groupurl != '') { teditor.addButton('quoteMessage', { tooltip: 'Quote post', icon: 'fa fa-comment', onclick: function () { editor.ShowMessageHistory(id, groupurl, 'html', '', sig, false); } }); } if (draftid != '' && draftid != '0' && draftid != 0) { teditor.on('NodeChange', function () { //tinymce.triggerSave(); if (tinymce.activeEditor != null) { let markupStr = tinymce.activeEditor.getContent(); $('#editor' + id).val(markupStr); modOnFormChange(id, draftid, groupurl, csrf); } }); teditor.on('keyup', function () { //tinymce.triggerSave(); let markupStr = tinymce.activeEditor.getContent(); $('#editor' + id).val(markupStr); modOnFormChange(id, draftid, groupurl, csrf); }); } if (isWiki == true) { // special wiki buttons teditor.addButton('addWikiImage', { tooltip: 'Insert image', icon: 'fa fa-image', onclick: function () { $('#ImageModal').modal({}); } }); teditor.addButton('addWikiLink', { tooltip: 'Insert link to wiki page', icon: 'fa fa-book', onclick: function () { $('#LinkModal').modal({}); } }); teditor.addButton('addWikiTOC', { tooltip: 'Insert table of contents', icon: 'fa fa-list-alt', onclick: function () { $('#TOCModal').modal({}); } }); } } }); } else { tinymce.init({ branding: false, link_context_toolbar: true, default_link_target: '_blank', link_assume_external_targets: true, elementpath: false, forced_root_block: forceRootBlock, content_css: css, relative_urls: false, remove_script_host: false, menubar: false, statusbar: true, plugins: plugins, toolbar1: small_toolbar1, toolbar2: small_toolbar2, font_formats: tm_fonts, browser_spellcheck: true, contextmenu: false, selector: '#editor' + id, resize: true, fontsize_formats: fontsizes, style_formats: style_formats, setup: function (teditor) { teditor.on('Init', function (e) { // see if any text is selected toquote = modGetSelection(id); if (toquote != '') { console.log('id=' + id); editor.ShowMessageHistory(id, groupurl, 'html', toquote, sig, true); } else { if (body != "") { console.log("body setContent"); teditor.setContent(body); } else if (sig != "") { console.log("sig setContent" + sig); teditor.setContent(sig); } } if (onInitFunc != null) { onInitFunc(e); } }); teditor.on('BeforeRenderUI', function (e) { teditor.theme.panel .find('toolbar') .slice(1) .hide(); }); teditor.addButton('advancedToolbar', { tooltip: 'Show advanced toolbar', icon: 'fa fa-bars', onclick: function () { if (!this.active()) { this.active(true); teditor.theme.panel .find('toolbar') .slice(1) .show(); } else { this.active(false); teditor.theme.panel .find('toolbar') .slice(1) .hide(); } } }); teditor.addButton('addPictures', { tooltip: 'Add pictures', icon: 'fa fa-image', onclick: function () { modUploaderPrompt("pictures", id, draftid, groupurl, csrf); } }); teditor.addButton('addAttachments', { tooltip: 'Add attachments', icon: 'fa fa-paperclip', onclick: function () { modUploaderPrompt("attachments", id, draftid, groupurl, csrf); } }); if (groupurl != '') { teditor.addButton('quoteMessage', { tooltip: 'Quote post', icon: 'fa fa-comment', onclick: function () { editor.ShowMessageHistory(id, groupurl, 'html', '', sig, false); } }); } if (draftid != '' && draftid != '0' && draftid != 0) { teditor.on('NodeChange', function () { if (tinymce.activeEditor != null) { //tinymce.triggerSave(); let markupStr = tinymce.activeEditor.getContent(); $('#editor' + id).val(markupStr); modOnFormChange(id, draftid, groupurl, csrf); } }); teditor.on('keyup', function () { //tinymce.triggerSave(); let markupStr = tinymce.activeEditor.getContent(); $('#editor' + id).val(markupStr); modOnFormChange(id, draftid, groupurl, csrf); }); } // special wiki buttons teditor.addButton('addWikiImage', { tooltip: 'Add Image', icon: 'fa fa-image', onclick: function () { $('#ImageModal').modal({}); } }); teditor.addButton('addWikiLink', { tooltip: 'Add Link', icon: 'fa fa-book', onclick: function () { $('#LinkModal').modal({}); } }); teditor.addButton('addWikiTOC', { tooltip: 'Table of Contents', icon: 'fa fa-list-alt', onclick: function () { $('#TOCModal').modal({}); } }); } }); // disable tooltips because they require double taps on mobile $('.note-editor *').tooltip('disable'); } }, initPlainEditor: function (id, bodyType, groupurl, handleAttachments, sig) { $('#addattachments').show(); if (bodyType == 'plain') { $('#bodytype' + id).val('plain'); $('#preview' + id).hide(); $('#return' + id).hide(); $('#preview' + id).hide(); $('#markdownlink' + id).hide(); } else { $('#bodytype' + id).val('markdown'); $('#markdownbuttons' + id).show(); $('#preview' + id).show(); $('#return' + id).hide(); $('#previewWindow' + id).hide(); $('#markdownlink' + id).show(); } toquote = modGetSelection(id); if (toquote != '') { editor.ShowMessageHistory(id, groupurl, 'plain', toquote, sig, true); //$('#editor' + id).val(toquote); } }, InitPostDraft: function (id, draftid, csrf, groupurl) { // save the draft when leaving the page. $(window).on('beforeunload', function () { modUnloading = true; modSaveDraft(id, draftid, groupurl, csrf, true); }); // save the draft 1 second after a change $('form input, form textarea').on('input propertychange change', function () { modOnFormChange(id, draftid, groupurl, csrf); }); modUpdateAttachments(id, draftid, csrf, groupurl); if (typeof Capacitor !== 'undefined') { modInitDeviceUploader(id, draftid, csrf, groupurl); } else { modInitWebUploader(id, draftid, csrf, groupurl); } }, // InitReplyDraft creates a new draft, assumes a hidden form input called #draftidmid, and then calls initWindow(). InitReplyDraft: function ( id, bodytype, draftid, groupurl, csrf, handleAttachments, noFontChanges, isReply, isWiki, body, sig, onInitFunc ) { console.log('in InitReplyDraft draftid=' + draftid); modDeletedDraft = false; modDestroyedEditor = false; modUnloading = false; if (draftid == 0) { // create a new draft console.log('generating new draft' + groupurl); console.log('id=' + id); upload = { mid: id, csrf: csrf, body: sig }; $.ajax({ url: groupurl + '/reply', cache: false, method: 'POST', data: upload, xhrFields: { withCredentials: true }, dataType: 'json', error: function (xhr, ajaxOptions, thrownError) { if (modDeletedDraft == false && modDestroyedEditor == false) { createAlert("There was an error saving the draft. Please reload the page.", true, false) } } }).done(function (response) { console.log('reply draft created'); console.log('draftid:' + response.DraftID); draftid = response.DraftID; $('#draftid' + id).val(response.DraftID); editor.InitEditor( id, bodytype, draftid, groupurl, csrf, handleAttachments, noFontChanges, true, false, body, sig, onInitFunc ); editor.InitPostDraft(id, draftid, csrf, groupurl); console.log('id=' + id); $('#bodytype' + id).val(bodytype); $('#cancel-' + id).attr( 'onclick', 'editor.discardReplyDraft("' + id + '", "' + draftid + '","' + bodytype + '","' + csrf + '","' + groupurl + '");' ); return; }); return; } editor.InitEditor( id, bodytype, draftid, groupurl, csrf, handleAttachments, noFontChanges, true, false, body, sig, onInitFunc ); editor.InitPostDraft(id, draftid, csrf, groupurl); $('#bodytype' + id).val(bodytype); $('#cancel-' + id).attr( 'onclick', 'editor.discardReplyDraft("' + id + '", "' + draftid + '","' + bodytype + '","' + csrf + '","' + groupurl + '");' ); console.log('DONE'); }, // discardReplyDraft deletes the draft and any attachments and returns the user to the previous page. discardReplyDraft: function (id, draftid, bodytype, csrf, groupurl) { console.log('editor delete reply draft'); upload = { draftid: draftid, csrf: csrf, jsondelete: '1' }; $.ajax({ url: groupurl + '/draftop', cache: false, data: upload, method: 'POST', xhrFields: { withCredentials: true }, dataType: 'json' }).done(function (response) { // Do something with the request console.log("success delete reply draft"); $('#draftid' + id).val(''); if (bodytype == 'html') { tinymce.get('editor' + id).remove(); } $('#subject' + id).val($('#origsubject' + id).val()); $('#editor' + id).val(''); modDeletedDraft = true; modDestroyedEditor = true; }); }, PreviewMarkdown: function (id, groupurl) { let markdown = $('#editor' + id).val(); upload = { md: markdown }; $.ajax({ url: groupurl + '/previewmd', cache: false, data: upload, method: 'POST', xhrFields: { withCredentials: true }, dataType: 'json' }).done(function (response) { // Do something with the request console.log(response.markdown); wrap = '

' + response.markdown + '

'; $('#editwindow' + id).hide(); $('#previewWindow' + id).replaceWith(wrap); $('#previewWindow' + id).show(); }); $('#preview' + id).hide(); $('#return' + id).show(); }, ReturnMarkdown: function (id) { $('#preview' + id).show(); $('#return' + id).hide(); $('#previewWindow' + id).hide(); $('#editwindow' + id).show(); }, ClearTimeout: function() { clearTimeout(modTimeoutId); }, ShowMessageHistory: function( id, groupurl, bodytype, selectedText, sig, firstTime ) { console.log('URL ' + groupurl); console.log('ID ' + id); if (bodytype == 'html' && firstTime == false) { existingmsg = tinyMCE.get('editor' + id).getContent(); } else { existingmsg = $('#editor' + id).val(); } if (selectedText == '') { upload = { preview: bodytype, id: id }; } else { upload = { preview: bodytype, id: id, text: selectedText }; if (firstTime == true) { existingmsg = sig; } } $.ajax({ url: groupurl + '/previewmd', cache: false, data: upload, method: 'POST', xhrFields: { withCredentials: true }, dataType: 'json' }).done(function (response) { $('#editor' + id).val(response.reply + existingmsg); if (bodytype == 'html') { console.log('SETTING ' + response.reply + existingmsg); tinyMCE.get('editor' + id).setContent(response.reply + existingmsg); tinyMCE.get('editor' + id).selection.select(tinyMCE.get('editor' + id).getBody(), true); tinyMCE.get('editor' + id).selection.collapse(false); console.log('DONE'); } }); $('#editor' + id).focus(); } /* $('form').submit(function(e) { clearTimeout(modTimeoutId); if (postVar != null) { postVar.abort(); } console.log("SETTING DELETED TO TRUE"); console.log("EVENT:", e); modDeletedDraft = true; if ($(this).hasClass('form-submitted')) { e.preventDefault(); return; } $(this).addClass('form-submitted'); }); */ };}());async function uploadAttachments(doctype, id, draftid, groupurl, csrf) { const result = await Capacitor.Plugins.FilePicker.pickFiles(); const file = result.files[0]; console.log("in uploadAttachments"); console.log("files:", result.files); console.log("mimeType:", file.mimeType); console.log("name:", file.name); console.log("doctype:", doctype);const b64toBlob = (base64, type = 'image/jpeg') => fetch(`data:${type};base64,${base64}`).then(res => res.blob());const result2 = await Capacitor.Plugins.Filesystem.readFile({path:file.path})console.log("result2: ", result2);const blob = await b64toBlob(result2.data, file.mimeType);console.log("in uploadAttachments 2, " + file.mimeType); uploadImage(doctype, id, draftid, groupurl, csrf, blob, file.name);}async function takePicture2(doctype, id, draftid, groupurl, csrf) { console.log("in takePicture2"); try { const image = await Capacitor.Plugins.Camera.getPhoto({ quality: 90, allowEditing: false, resultType: "uri" }); console.log("got image");const b64toBlob = (base64, type = 'image/jpeg') => fetch(`data:${type};base64,${base64}`).then(res => res.blob());const result = await Capacitor.Plugins.Filesystem.readFile({path:image.path})const blob = await b64toBlob(result.data);console.log("path: ", image.path); uploadImage(doctype, id, draftid, groupurl, csrf, blob, image.path.split("/").pop()); } catch (err) { console.log("catch err 1: ", err); }}async function uploadImage(doctype, id, draftid, groupurl, csrf, raw, name) { console.log("here0"); const controller = new AbortController(); const formData = new FormData(); console.log("here1"); formData.append("csrf", csrf); formData.append("draftid", draftid); formData.append("upload", "1"); if (doctype === "pictures") { formData.append("inline", "1"); } console.log("FORMDATA:", formData); formData.append("fileupload", raw, name); console.log("here3"); const myRequest = new Request(groupurl + '/draftop', { method: 'POST', credentials: 'include', body: formData, signal: controller.signal, mode: 'cors' }); console.log("uploading"); try { const response = await fetch(myRequest); const result = await response.json(); if (doctype === "pictures") { console.log("picture processing"); for (let i = result.length - 1; i >= 0; i--) { console.log("Processing: ", i); const fileurl = result[i]; console.log('FILE: ' + result[i]); console.log('URL: ' + fileurl); const imghtml = 'Command line decoder for NRSC5 (aka HD Radio here in the US) now available for SDRplay RSPs (1)'; console.log('imghtml: ' + imghtml); tinymce.activeEditor.insertContent(imghtml); } } else { console.log("attachment processing"); updateAttachments(id, draftid, csrf, groupurl); console.log("attachment processing done"); } } catch (error) { console.error('Error:', error); }}

  1. SDRPlayUsers
  2. Topics

Search

DateDate1 - 20 of 24

  • previous page
  • next page

Command line decoder for NRSC5 (aka HD Radio here in the US) now available for SDRplay RSPs#rsp

Franco Venturi

  • All Messages By This Member

#3536


I ported the command line decoder for NRSC5 to use the SDRplay RSPs directly via the SDRplay API driver version 3.X

For those not familiar with NRSC5, it is the standard adopted by the FCC for digital commercial broadcasting in the FM band here in the US (and I think on AM too, although I am not very familiar with it): it is commonly known here as 'HD Radio'.

The code, along with precompiled binaries for Windows (32 and 64 bit) and MacOS, is here: https://github.com/fventuri/nrsc5
Instructions on how to install and run the binaries for Windows and MacOS are here: https://github.com/fventuri/nrsc5#installing-and-running-the-precompiled-binaries-for-sdrplay

A few important notes:
- the program is command line only, i.e. you will have to run it from a 'command window (CMD)' in Windows or from a 'terminal' in MacOS
- while the program is running, you can change the digital channel of the selected FM station by entering the number 0, 1, 2, or 3 - you can also exit program by typing 'q'
- the code is a quick port for SDRplay (and for other SoapySDR devices) of the original NRSC5 decoder by theori.io (https://github.com/theori-io/nrsc5)
- since it uses the SDRplay API directly, it doesn't require any other program (like RSPTCP) to run; it also cannot be run at the same time as another program accessing the same RSP device
- this program is not supported or endorsed by SDRplay; for any problem with it (crashes, doesn't run, doesn't decode, lack of documentation, instructions are not clear enough, etc), please create a new issue here: https://github.com/fventuri/nrsc5/issues), or leave some feedback here.

I hope you have fun playing with it!
Franco - K4VZ

Bob Dengler

  • All Messages By This Member

#3537


At 6/5/2021 01:24 PM, you wrote:

I ported the command line decoder for NRSC5 to use the SDRplay RSPs directly via the SDRplay API driver version 3.X

Zip file is password protected.

Bob NO6B

Franco Venturi

  • All Messages By This Member

#3539


Bob,
sorry, I didn't realize the header with the licenses didn't show when you try to open the file (it did here when I tried it).

Since those licenses (which I had to include because of the precompiled binary distribution) are long here is just the beginning and end of it:

GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble

The GNU General Public License is a free, copyleft license for
software and other kinds of works.

..........(full licenses text)..........

Type 'accept all licenses' as the password below.

73,
Franco - K4VZ

Bob Dengler

  • All Messages By This Member

#3541


At 6/5/2021 06:30 PM, you wrote:

Bob,
sorry, I didn't realize the header with the licenses didn't show when you try to open the file (it did here when I tried it).

Type 'accept all licenses' as the password below.

Thanks Franco. Works great! I used to use the RTL-SDR version until I lost my Nooelec SDR, so this lets me listen to HD FM again.

Bob NO6B

j.vankatwjk

  • All Messages By This Member

#3542


Interesting, Is there somewhere a reasonable (technical) description of HD Radio, is it e.g. (more or less) similar to what DAB or DRM+ is using?

best

jan


Op za 5 jun. 2021 om 22:56 schreef Franco Venturi <fventuri@...>:

toggle quoted messageShow quoted text

I ported the command line decoder for NRSC5 to use the SDRplay RSPs directly via the SDRplay API driver version 3.X

For those not familiar with NRSC5, it is the standard adopted by the FCC for digital commercial broadcasting in the FM band here in the US (and I think on AM too, although I am not very familiar with it): it is commonly known here as 'HD Radio'.

The code, along with precompiled binaries for Windows (32 and 64 bit) and MacOS, is here: https://github.com/fventuri/nrsc5
Instructions on how to install and run the binaries for Windows and MacOS are here: https://github.com/fventuri/nrsc5#installing-and-running-the-precompiled-binaries-for-sdrplay

A few important notes:
- the program is command line only, i.e. you will have to run it from a 'command window (CMD)' in Windows or from a 'terminal' in MacOS
- while the program is running, you can change the digital channel of the selected FM station by entering the number 0, 1, 2, or 3 - you can also exit program by typing 'q'
- the code is a quick port for SDRplay (and for other SoapySDR devices) of the original NRSC5 decoder by theori.io (https://github.com/theori-io/nrsc5)
- since it uses the SDRplay API directly, it doesn't require any other program (like RSPTCP) to run; it also cannot be run at the same time as another program accessing the same RSP device
- this program is not supported or endorsed by SDRplay; for any problem with it (crashes, doesn't run, doesn't decode, lack of documentation, instructions are not clear enough, etc), please create a new issue here: https://github.com/fventuri/nrsc5/issues), or leave some feedback here.

I hope you have fun playing with it!
Franco - K4VZ


--

Jan van Katwijk

Franco Venturi

  • All Messages By This Member

#3543


Jan,
the latest official specification of the NRSC-5 standard (version NRSC-5-D) is available for free here: https://www.nrscstandards.org/standards-and-guidelines/documents/standards/nrsc-5-d/nrsc-5-d.pdf

You'll notice that the NRSC-5 standard specifies modulation, error correction, channel coding, interleaving, etc, but does not say how the audio streams should be encoded; that is left to the implementer. In the US the implementer is Ibiquity (https://en.wikipedia.org/wiki/IBiquity); if you are in the US and have a car radio that can listen to HD Radio you usually see their logo next to the words 'HD Radio'.

The significant thing about the work from theori.io is that they figured out that the HD Radio audio stream codec is just a slightly modified version of HE-AAC - their research is documented in this very interesting post that I recommend: https://blog.theori.io/research/nrsc-5-c/

As you noticed, NRSC-5 and DAB+ are kind of 'cousins', since they both use COFDM for their modulation and their codecs are AAC+ and a derivative of HE-AAC - the Wikipedia page on HD Radio (https://en.wikipedia.org/wiki/HD_Radio) is another very interesting read, and has a section where they compare HD radio with DAB/DAB+ and with DRM.

Finally I forgot yesterday to mention that for those who prefer a graphic UI instead of a command line interface, there are at least two programs that I know of that offer a GUI to control the same command line nsrc5 decoder, and therefore should work with this version too (but I haven't tried them):

- NRSC5-DUI: https://www.rtl-sdr.com/nrsc5-dui-an-updated-nrsc-5-hd-radio-decoder-for-rtl-sdr

j.vankatwjk

  • All Messages By This Member

#3545


Franco,

Thanks for the links, very interesting!

Here in Europe we are moving slowly - but steadily - towards DAB+, In Norway FM is completely abandoned and DAB is the system of choice.

DAB+ here in the Netherlands is typically implemented as Single Frequency Network; with a small antenna I receive in some channels simultaneously data from

4 to 5 transmitters, most of them 10 to 20 Km away.

I have written a DAB/DAB+ decoder for use on PC (Linux and Windows) and RPI (Qt-DAB)

Variants are a library with some command line examples, one with an extensive GUI and one with a minimal GUI,

As an experiments - basically a gadget - the Qt-DAB software -usng a Adalm Pluto device - the audio from a selected audio service is retransmitted as an FM

signal.

I also wrote some software for DRM and DRM+, there are not much DRM transmission here, but technique is interesting. I even wrote a plugin for SDRuno for

running DRM (not officially released though).

I do not know about HDRadio, but for DRM one needs a reasonable signal, I get transmissions from Romenia (2000 Km( abd usually there is quite some fading

and signal loss

I'll study both the standard and the implementation for HDRadio, thanks for the effort

best

jan


Op zo 6 jun. 2021 om 15:46 schreef Franco Venturi <fventuri@...>:

toggle quoted messageShow quoted text

Jan,
the latest official specification of the NRSC-5 standard (version NRSC-5-D) is available for free here: https://www.nrscstandards.org/standards-and-guidelines/documents/standards/nrsc-5-d/nrsc-5-d.pdf

You'll notice that the NRSC-5 standard specifies modulation, error correction, channel coding, interleaving, etc, but does not say how the audio streams should be encoded; that is left to the implementer. In the US the implementer is Ibiquity (https://en.wikipedia.org/wiki/IBiquity); if you are in the US and have a car radio that can listen to HD Radio you usually see their logo next to the words 'HD Radio'.

The significant thing about the work from theori.io is that they figured out that the HD Radio audio stream codec is just a slightly modified version of HE-AAC - their research is documented in this very interesting post that I recommend: https://blog.theori.io/research/nrsc-5-c/

As you noticed, NRSC-5 and DAB+ are kind of 'cousins', since they both use COFDM for their modulation and their codecs are AAC+ and a derivative of HE-AAC - the Wikipedia page on HD Radio (https://en.wikipedia.org/wiki/HD_Radio) is another very interesting read, and has a section where they compare HD radio with DAB/DAB+ and with DRM.

Finally I forgot yesterday to mention that for those who prefer a graphic UI instead of a command line interface, there are at least two programs that I know of that offer a GUI to control the same command line nsrc5 decoder, and therefore should work with this version too (but I haven't tried them):

- NRSC5-DUI: https://www.rtl-sdr.com/nrsc5-dui-an-updated-nrsc-5-hd-radio-decoder-for-rtl-sdr


--

Jan van Katwijk

W4RLS
  • All Messages By This Member

#3554


Thanks, Franco. This is really cool. It's also very light on CPU usage.

Bob, W4RLS

HB

  • All Messages By This Member

#3560


Thanks Franco!!! I have several HD radio stations in my area.

2 comments - the software still needs a password after download from github for Windows. - 2nd, the instructions there indicate the syntax to start the software is 'nrs5-64 89.9 0' - it should read nrsc5-64 89.9 0

Thanks again!
Hank
K4HYJ

Franco Venturi

  • All Messages By This Member

#3569


Hank, thanks for your kind words.

The files with the binary builds for Windows 32, Windows 64, and MacOS contain a non-encrypted header with the licenses that begins and ends like this:

GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

.....

Type 'accept all licenses' as the password below.

I had to add that because the FAAD2 decoder used to decode the audio streams has a license (see here: https://en.wikipedia.org/wiki/FAAC#Licensing), that I think may require to be accepted explicitly when built into a binary.
I do see the header with the licenses and the password here on Linux when I run 'unzip <filename>', but it looks like it doesn't show on Windows.
If someone knows a more user friendly way to achieve that that works on Windows and MacOS, I am definitely interested in changing the way the binary executables get distributed (they both get built automatically by the GitHub CI whenever there's a commit with a new release tag).

Also thanks for noticing the typos in the README file; they are fixed now.

73,
Franco - K4VZ

@KC2TAU

  • All Messages By This Member

#5214


I'm having a bit of difficulty using this program under Windows 10. Each time I attempt to launch the program from a command line it returns the error of:

"'nrsc-64' is not recognized as an internal or external command,
operable program or batch file."

I've made sure that the executable is in my PATH. I'm a bit confused as to why I am receiving this error. Any help would be greatly appreciated. Thank you.

Franco Venturi

  • All Messages By This Member

#5216


I think the program is called 'nrsc5-64', not 'nrsc-64'.

Franco

@KC2TAU

  • All Messages By This Member

#5217


Hello Franco,

Thank you! I have it working now. I have one question about one of the arguments. When using the -g argument for determining the gain of the SDR when you have an SDRPlay receiver is the correct way to write it "-g IFGR=0"? I keep receiving an error of "invalid gain" when I try to type it this way.

Jon Hudson

  • All Messages By This Member

#5219


For anyone interested in NRSC5, this video demonstrates HD Radio decoding if you wind forward to 18 minutes 20 seconds:https://youtu.be/jMYUvOPHwno

Franco Venturi

  • All Messages By This Member

#5222


Jon, thanks for the link to the video!

KC2TAU,
if you are using the nrsc5-64 program that uses the native SDRplay API (there's another version that uses SoapySDR but you have to compile that one from source), then the gain value is passed as a pseudo floating point value where the integer part represents the desired RSP LNA state and the decimal part (just the two most significant digits) represent the IF gain reduction (which normally is in the the range 20-59; the special value '0' enables the AGC) - see also here: https://github.com/fventuri/nrsc5/blob/master/README.md?plain=1#L149
For instance to have the RF LNA state set to say 3 and the IF gain reduction set to 40, you would use '-g 3.40'; to have the RF LNA state set to to 1 and IF AGC enabled, you would use '-g 1.0' (or simply '-g 1'), and so on.

73,
Franco K4VZ

Rob Keeney

  • All Messages By This Member

#5565


Hi Franco,

I'm getting

c:\HDdecoder nrsc5-64 97.1 0

06:45:11 Open device failed.

running with RSPDuo. I've copied the API dll 3.09 into the HDdecoder dir and restarted the machine. Any ideas on this?

Thanks,
Rob Keeney

Franco Venturi

  • All Messages By This Member

#5568


Rob,
perhaps the problem is that I built that release a while a ago when the SDRplay API for Windows was at version 3.07.
This morning I created a new release (0.1.1) using the latest SDRplay API for Windows (i.e. version 3.09).
I just ran a quick test listening to a couple of HD channels from a local FM station and it worked for me.

You can find the zips with the updated binaries here: https://github.com/fventuri/nrsc5/releases/tag/v0.1.1

Hope it works for you too,
Franco

Rob Keeney

  • All Messages By This Member

#5569


Hi Franco,

I downloaded the new zip for Windows 64 bit, but I'm still getting the same "Open device failed." message. I'm not running any plugins, RDS or anything else.

Thanks,
Rob

Randy-W4LKS
  • Member Profile
  • All Messages By This Member

#5574


Those zip files appear to be password protected. Can you give me a hint? Randy

On 3/29/2022 6:36 AM, Franco Venturi wrote:

toggle quoted messageShow quoted text

Rob,
perhaps the problem is that I built that release a while a ago when the SDRplay API for Windows was at version 3.07.
This morning I created a new release (0.1.1) using the latest SDRplay API for Windows (i.e. version 3.09).
I just ran a quick test listening to a couple of HD channels from a local FM station and it worked for me.

You can find the zips with the updated binaries here: https://github.com/fventuri/nrsc5/releases/tag/v0.1.1

Hope it works for you too,
Franco

Franco Venturi

  • All Messages By This Member

#5580


@Rob: sorry for answering you only now, but I had a very busy day at work.
I just created a new debug release (v0.1.1-debug - https://github.com/fventuri/nrsc5/releases/tag/v0.1.1-debug), that should print some additional debug messages, and hopefully show us where is the problem; please try this debug version and let me know what it prints out over there.

@Randy: the password is 'accept all licenses' - please see this post https://groups.io/g/SDRPlayUsers/message/3569 for further details.

Franco

1 - 20 of 24
  • previous page
  • 1
  • 2
  • next page

Previous TopicNext Topic

Command line decoder for NRSC5 (aka HD Radio here in the US) now available for SDRplay RSPs (2024)
Top Articles
Latest Posts
Article information

Author: Domingo Moore

Last Updated:

Views: 6393

Rating: 4.2 / 5 (53 voted)

Reviews: 84% of readers found this page helpful

Author information

Name: Domingo Moore

Birthday: 1997-05-20

Address: 6485 Kohler Route, Antonioton, VT 77375-0299

Phone: +3213869077934

Job: Sales Analyst

Hobby: Kayaking, Roller skating, Cabaret, Rugby, Homebrewing, Creative writing, amateur radio

Introduction: My name is Domingo Moore, I am a attractive, gorgeous, funny, jolly, spotless, nice, fantastic person who loves writing and wants to share my knowledge and understanding with you.