windows听电台方案

目前好像主要是mpv和vlc,我用的mpv,搜索几个mpv的包在windows上好像都不太正常,因为windows上不支持mpv的一个--input-ipc-server=参数,但有个包https://github.com/isamert/empv.el可以正常播放,只是其它功能不正常,于是我就只用了这个包的播放功能,然后抓取了https://www.radio-browser.info/上的中文音乐台,用普通的minibuffer选择电台,效果图: image

配置如下:

(use-package empv
  :defer t
  :init (autoload 'empv-play "tools/empv" nil t)
  ;; https://www.radio-browser.info/
  (defvar radio-urls nil)
  (defun radio-urls-read (file)
    "radio_urls.el由radio_urls_get.py生成"
    (with-temp-buffer
      (insert "(\n")
      (insert-file-contents file)
      (goto-char (point-max))
      (insert "\n)")
      (goto-char (point-min))
      (let ((data (read (current-buffer))))
        data)))
  (defun radio-select ()
    (interactive)
    (unless radio-urls
      (setq radio-urls
            (radio-urls-read
             (expand-file-name "packages/tools/radio_urls.el"
                               user-emacs-directory)))
      ;; 蜻蜓的音质基本都很差,仅下面这个可以
      (setq radio-urls
            (append
             '(("华语金曲500首"
                "http://ls.qingting.fm/live/3412131.m3u8?bitrate=64"))
             radio-urls)))
    (let* ((completion-ignore-case t)
           (item
            (assoc-string (completing-read "Radio select: " radio-urls
                                           nil t)
                          radio-urls
                          t)))
      (empv-play (nth 1 item))))
  (defalias 'radio-stop 'empv-exit)
  :config (add-to-list 'empv-mpv-args "--volume=70") ;; 默认声音太大
  ;; 目前仅支持播放/关闭功能,其它功能都有问题,有个参数socket-file在windows上是不支持的
  ;; 播放之前必须关闭之前的进程
  (advice-add #'empv-play :before (lambda (&rest _) (empv-exit))))

电台列表在 .emacs.d/packages/tools/radio_urls.el at master · lynnux/.emacs.d (github.com)里,提取电台列表的脚本在 .emacs.d/packages/tools at master · lynnux/.emacs.d (github.com) 电台我只听音乐,去掉了蜻蜓的源,因为我发现蜻蜓的电台音质一般都很差。

9 个赞

感谢,需要…

感谢, 已经用上了~

有个疑问,为什么不直接使用 ``empv-radio-channels呢?生成的 radio_urls./el 文件中直接赋值给它就可以了。我测试了如下代码是可以的(使用empv-play-radio`)

   (setq empv-radio-channels
        '(("华语金曲500首"                         . "http://ls.qingting.fm/live/3412131.m3u8?bitrate=64")
          ("CNR-3 音乐之声"                        . "http://ngcdn003.cnr.cn/live/yyzs/index.m3u8")
          ("CNR-4 经典音乐广播"                    . "http://ngcdn004.cnr.cn/live/dszs/index.m3u8")
          ("武汉音乐广播·动感93.6"                 . "http://ls.qingting.fm/live/5011.m3u8")
          ("上海经典音乐广播"                      . "http://l3.smgtech.net/AppName/1197.m3u8")
          ("武汉经典音乐广播·岁月悠长,听见好时光" . "http://ls.qingting.fm/live/1297.m3u8"))

我这里调用empv-play-radio会出错:

那个empv--network-process总是nil,因为那个empv-socket-file创建不成功,这就是那个mpv --input-ipc-server参数指定的socket file,貌似windows上不支持还是咋的,我也没细看,能够启动mpv进程,然后调用empv-exit停止播放就够用了。换台就停止再播放就可以了。

其实核心主要是电台列表,linux等平台能够正常使用empv-play-radio,可以按seagle0128大佬的方法设置empv-radio-channels。我只需要mpv进程启动/停止功能就够了,不用empv自己实现启动mpv也是可以的,只是懒得折腾了。

上午又弄了下,在mode line上显示当前播放的电台,绿色表达正在播放,红色表明已停止,仅在调用radio-select后显示,支持鼠标点击停止/播放。 效果图: image image

(use-package empv
  :defer t
  :init (autoload 'empv-play "tools/empv" nil t)
  ;; https://www.radio-browser.info/
  (defvar radio-urls nil)
  (defvar radio-url-current nil)
  (defun radio-urls-read (file)
    "radio_urls.el由radio_urls_get.py生成"
    (with-temp-buffer
      (insert "(\n")
      (insert-file-contents file)
      (goto-char (point-max))
      (insert "\n)")
      (goto-char (point-min))
      (let ((data (read (current-buffer))))
        data)))
  (defun radio-select ()
    (interactive)
    (unless radio-urls
      (setq radio-urls
            (radio-urls-read
             (expand-file-name "packages/tools/radio_urls.el"
                               user-emacs-directory)))
      ;; 蜻蜓的音质基本都很差,仅下面这个可以
      (setq radio-urls
            (append
             '(("华语金曲500首"
                "http://ls.qingting.fm/live/3412131.m3u8?bitrate=64"))
             radio-urls)))
    (let* ((completion-ignore-case t)
           (item
            (assoc-string (completing-read "Radio select: " radio-urls
                                           nil t)
                          radio-urls
                          t)))
      (setq radio-url-current item)
      (ignore-errors
        (empv-play (nth 1 item)))))
  (defalias 'radio-stop 'empv-exit)
  :config (add-to-list 'empv-mpv-args "--volume=70") ;; 默认声音太大
  ;; 目前仅支持播放/关闭功能,其它功能都有问题,有个参数socket-file在windows上是不支持的
  ;; 播放之前必须关闭之前的进程
  (advice-add #'empv-play :before (lambda (&rest _) (empv-exit)))

  ;; 添加mode-line指示,参考`display-time-string'
  (defvar radio-mode-string nil)
  (put 'radio-mode-string 'risky-local-variable t) ;; 必须不然face等没效果
  (defface radio-mode-line-face-playing '((t :foreground "#6ae4b9"))
    "")
  (defface radio-mode-line-face-stopped '((t :foreground "#CC6666"))
    "")
  (defun radio-mode-string-keymap-click (event)
    (interactive "e")
    (when radio-url-current
      (ignore-errors
        (if (empv--running?)
            (empv-exit)
          (empv-play (nth 1 radio-url-current))))))
  (defun radio-mode-string-update (&optional _)
    (setq radio-mode-string
          (if radio-url-current
              (propertize (concat " ⏯️️" (car radio-url-current))
                          'face
                          (if (empv--running?)
                              'radio-mode-line-face-playing
                            'radio-mode-line-face-stopped)
                          'mouse-face
                          'mode-line-highlight
                          'local-map
                          radio-mode-string-keymap)
            "")))
  (defvar radio-mode-string-keymap
    (let ((map (make-sparse-keymap)))
      (define-key
       map [mode-line mouse-1] 'radio-mode-string-keymap-click)
      map))
  (advice-add #'empv--make-process :after #'radio-mode-string-update)
  (advice-add #'empv-exit :after #'radio-mode-string-update)
  (setq global-mode-string
        (append global-mode-string '(radio-mode-string))))

Windows 下确实有这个问题,WSL下没有问题。见:Unable to Start empv radio on Windows 10 OS · Issue #48 · isamert/empv.el (github.com)

empv-play前调用 empv-exit 就不需要这个advice了

今天试了下,最简单就是用这个函数就行

(defun empv-play-radio+ ()
    "Play radio channels on Windows."
    (interactive)
    (let ((channel (assoc-string
                    (completing-read "Channel: " empv-radio-channels
                                     nil t)
                    empv-radio-channels
                    t)))
      (ignore-errors
        (empv-exit)
        (message "Now playing %s..." (car channel))
        (empv-play (cdr channel)))))

我后面改了几次没用empv这个包了,自己写个播放/停止功能就行了。也支持过foobar2000,不过foobar2000网络播放不太行,经常卡掉线,播放体验不如mpv。音质的话其实都是差不多的,听不出多大区别。win7上mpv最高版本20230917,而且win7上foobar网络下载就更不行,连url重定位都不支持,现在只用mpv了。 代码有点多,跟上面功能是一样的,上面用empv的代码少点,且只考虑了win平台:

;; foobar里需要设置
  ;; 1.添加歌曲不显示gui,Preference>Shell Integretion,Bring to front.. 去掉勾选
  ;; 2.缩小到托盘图标,【File】->【Preferences】->【Advanced】->【Display】->【Default User Interface】->【Windows minimize and close】勾选Minize hide,close exits
  ;; 3.提升音质WASAPI篇,官网 https://www.foobar2000.org/components 下载插件WASAPI shared output 0.6.21(这个支持64位) 7z解压放到components目录,重启。 Preferences>Playback>Output>Device选择WASAPI设备
  (defvar foobar-binary nil)
  (defvar foobar-running nil)
  (defun foobar-play (uri)
    (foobar-exit) ;; 当切换下一个比较耗时电台时开头仍然会串音
    ;; win7 foobar不能播放重定向的url,需要自己获取重定向后的URL
    (when (equal (list 6 1 7601) (w32-version))
      (setq uri
            (string-trim
             (shell-command-to-string
              (concat
               (expand-file-name "packages/tools/url_get_redirect.py"
                                 user-emacs-directory)
               " " uri)))))
    (w32-shell-execute nil foobar-binary "/hide")
    (w32-shell-execute nil foobar-binary (format "/play %s" uri))
    (setq foobar-running t))
  (defun foobar-exit ()
    (interactive)
    (w32-shell-execute nil foobar-binary "/hide")
    (w32-shell-execute nil foobar-binary "/stop") ;; 没必要/exit,不然后面再播放可能会显示Proccesing files对话框
    (setq foobar-running nil))
  (defun foobar-is-running ()
    foobar-running)

  ;; mpv
  (defvar mpv-binary nil)
  (defvar mpv-process nil)
  (defvar empv-mpv-args
    `("--no-video" "--no-terminal" "--idle" "--volume=65"))
  (defun mpv-exit ()
    (interactive)
    (ignore-errors
      (when mpv-process
        (setq mpv-process (delete-process mpv-process)))))
  (defun mpv-play (uri)
    (mpv-exit)
    (setq mpv-process
          (make-process
           :name "empv-process"
           :buffer nil
           :command `(,mpv-binary ,@empv-mpv-args ,uri))))
  (defun mpv-is-running ()
    mpv-process)

  ;; radio
  (defun radio-switch-backend (&optional backend)
    (interactive)
    (unless backend
      (setq backend
            (completing-read
             "Radio backend select: " '("foobar" "mpv")
             nil t)))
    (when (and (fboundp 'radio-is-running) (radio-is-running))
      (radio-exit))
    (if (equal backend "foobar")
        (progn
          (defalias 'radio-play 'foobar-play)
          (defalias 'radio-exit 'foobar-exit)
          (defalias 'radio-is-running 'foobar-is-running))
      (defalias 'radio-play 'mpv-play)
      (defalias 'radio-exit 'mpv-exit)
      (defalias 'radio-is-running 'mpv-is-running)))

  ;; 音质其实都差不多,mpv下载要快点不卡。mpv支持win7最后版本20230917
  (radio-switch-backend "mpv")

  ;; https://www.radio-browser.info/
  (defvar radio-urls nil)
  (defvar radio-url-current nil)
  (defun radio-urls-read (file)
    "radio_urls.el由radio_urls_get.py生成"
    (with-temp-buffer
      (insert "(\n")
      (insert-file-contents file)
      (goto-char (point-max))
      (insert "\n)")
      (goto-char (point-min))
      (let ((data (read (current-buffer))))
        data)))
  (defun radio-select ()
    (interactive)
    (unless radio-urls
      (setq radio-urls
            (radio-urls-read
             (expand-file-name "packages/tools/radio_urls.el"
                               user-emacs-directory)))
      ;; 蜻蜓的音质基本都很差,仅下面这个可以
      (setq radio-urls
            (append
             '(("华语金曲500首"
                "http://ls.qingting.fm/live/3412131.m3u8?bitrate=64"))
             radio-urls)))
    (let* ((completion-ignore-case t)
           (item
            (assoc-string (completing-read "Radio select: " radio-urls
                                           nil t)
                          radio-urls
                          t)))
      (setq radio-url-current item)
      (ignore-errors
        (radio-play (nth 1 item)))))
  (defalias 'radio-stop 'radio-exit)
  ;; 添加mode-line指示,参考`display-time-string'
  (defvar radio-mode-string nil)
  (put 'radio-mode-string 'risky-local-variable t) ;; 必须不然face等没效果
  (defface radio-mode-line-face-playing '((t :foreground "#6ae4b9"))
    "")
  (defface radio-mode-line-face-stopped '((t :foreground "#CC6666"))
    "")
  (defun radio-mode-string-keymap-click (event)
    (interactive "e")
    (when radio-url-current
      (ignore-errors
        (if (radio-is-running)
            (radio-exit)
          (radio-play (nth 1 radio-url-current))))))
  (defun radio-mode-string-update (&optional _)
    (setq radio-mode-string
          (if radio-url-current
              (propertize (concat " ⏯️️" (car radio-url-current))
                          'face
                          (if (radio-is-running)
                              'radio-mode-line-face-playing
                            'radio-mode-line-face-stopped)
                          'mouse-face
                          'mode-line-highlight
                          'local-map
                          radio-mode-string-keymap)
            "")))
  (defvar radio-mode-string-keymap
    (let ((map (make-sparse-keymap)))
      (define-key
       map [mode-line mouse-1] 'radio-mode-string-keymap-click)
      map))
  (advice-add #'foobar-play :after #'radio-mode-string-update)
  (advice-add #'foobar-exit :after #'radio-mode-string-update)
  (advice-add #'mpv-play :after #'radio-mode-string-update)
  (advice-add #'mpv-exit :after #'radio-mode-string-update)
  (setq global-mode-string
        (append global-mode-string '(radio-mode-string)))

mpvi 的作者在 emms 中做了修改, 可以在window上 使用mpv交互。

有坛友研究过软件无线电(Software Defined Radio)吗?最近有点想听原汁原味的广播电台了 :joy:

我以前倒折腾过一些,现在没空玩了,分享你收集的一些工具,具体听电台需要自己组合来用。

硬件我用的是sdr最便宜的 https://www.rtl-sdr.com/buy-rtl-sdr-dvb-t-dongles/ rtl-sdr的设备官网买的,我杭州大概几天就到了,上海发的货。你可以买套件带天线的那款,我个人是买了裸设备 再加了天线。

软件我用的是 librtlsdr rx_tools 这两个项目里有一堆二进制rtl 工具可以快速组合搭建出你要原型。里面有一个叫rtl_fm的工具,应该是你要的收听fm广播需要用到的。

除了这些二进制工具还有就是用gnuradio用gnuradio 或者用python包装librtlsdr的pyrtlsdr 或者直接用librtlsdr这类库去更细致的折腾。

1 个赞

感谢提供经验 :pray: