潍坊网站设计好处,个体户 建设网站,wordpress首页轮播,牡丹江最新信息网项目的背景 最近开始听喜马拉雅播客的内容#xff0c;但是发现许多不方便的地方。 休息的时候收听喜马拉雅#xff0c;但是还需要不断地选择喜马拉雅的内容#xff0c;比较麻烦#xff0c;而且黑灯操作反而伤眼睛。 喜马拉雅为代表的播客平台都是VOD 形式的#xff0…
项目的背景 最近开始听喜马拉雅播客的内容但是发现许多不方便的地方。 休息的时候收听喜马拉雅但是还需要不断地选择喜马拉雅的内容比较麻烦而且黑灯操作反而伤眼睛。 喜马拉雅为代表的播客平台都是VOD 形式的需要选择内容收听有时候想听科技方面的访谈但是许多访谈节目并不是连续更新播放的。免不了要去主动查找。 休闲或者开车时希望收听收音机那样轻松一点地享受电台安排的节目但是目前的电台广告太多内容匮乏。家里的老人更不习惯手机操作。老人目前主要是看短视频。 笔者看来播客是一个被低估的服务其实依靠短视频很难接收有效的信息靠几分钟很难讲清楚一个观点和知识。所以要完整地了解一些有用的内容语音比短视频更好。 那么能否通过AI 推荐技术讲播客内容主动生成个人定制的音频频道吗理论上是可能的也十分有趣。作为一名创客我想试试。 说干就干本文介绍实验平台的搭建。
基于ardunio ESP32 的选台器 电子设备中经常使用旋钮来选择参数最简单的是旋钮是电位器它是一个滑动电阻高端家电汽车中使用的是编码器Encoder。编码器输出的是脉冲信号。本文介绍如何使用Ardunio ESP32-Nano 来设计一个蓝牙旋转编码器。
外观设计 硬件设计 细节
编码器
下面是日本ALPS 公司的中空旋转编码器EC35A。 三个引脚分别是ACB。 接线图 最好在编码器脉冲计数处理回路中设置下图所示的滤波器。 与Ardunio 的连接图。 代码
目前的代码使用了蓝牙mouse 仿真最终的程序也许要改成ble server 。
#include BleMouse.h
BleMouse bleMouse;
// Define the pins used for the encoder
const int encoderPinA 11;
const int encoderPinB 10;// Variables to keep the current and last state
volatile int encoderPosCount 0;
int lastEncoded 0;
int MAX60;
int channel-1;
void setup() {Serial.begin(115200);// Set encoder pins as input with pull-up resistorspinMode(encoderPinA, INPUT_PULLUP); pinMode(encoderPinB, INPUT_PULLUP);// Attach interrupts to the encoder pinsattachInterrupt(digitalPinToInterrupt(encoderPinA), updateEncoder, CHANGE);attachInterrupt(digitalPinToInterrupt(encoderPinB), updateEncoder, CHANGE);bleMouse.begin();
}void loop() {static int lastReportedPos -1; // Store the last reported positionif (encoderPosCount ! lastReportedPos) {if((encoderPosCount/2)channel) {channel; Serial.print(Encoder Position: );Serial.println(channel);bleMouse.move(0,0,1);};if((encoderPosCount/2)channel) {channel--; Serial.print(Encoder Position: );Serial.println(channel);bleMouse.move(0,0,-1);}lastReportedPos encoderPosCount;}delay(500) ;}void updateEncoder() {int MSB digitalRead(encoderPinA); // MSB most significant bitint LSB digitalRead(encoderPinB); // LSB least significant bitint encoded (MSB 1) | LSB; // Converting the 2 pin value to single numberint sum (lastEncoded 2) | encoded; // Adding it to the previous encoded valueif(sum 0b1101 || sum 0b0100 || sum 0b0010 || sum 0b1011){if (encoderPosCountMAX) encoderPosCount0;elseencoderPosCount;} if(sum 0b1110 || sum 0b0111 || sum 0b0001 || sum 0b1000){if (encoderPosCount0) encoderPosCountMAX;elseencoderPosCount--;} lastEncoded encoded; // Store this value for next time
} ardunio-ESP32-nano 开发板
外观 引脚图 HLS 网络电台的构建 HLS 全称是 HTTP Live Streaming 是一个由 Apple 公司实现的基于 HTTP 的媒体流传输协议。 借助 HLS视频和音频内容被分解为一系列块经过压缩以便快速交付并通过 HTTP 传输到最终用户的设备。 HLS 由一个m3u8 文件和多个ts 文件构成的。
节目源
网络上有许多网络广播电台的m3u8 的节目源地址有的可以播放有的不行。我们下载之后转换成为CSV 格式然后通过CSV2JSON.js 软件转化为json 文件.下面是一部分
[{StationName: 本地音乐台,URL: media/1.m3u8},{StationName: CGTN Radio,URL: http://sk.cri.cn/am846.m3u8},{StationName: CRI环球资讯广播,URL: http://satellitepull.cnr.cn/live/wxhqzx01/playlist.m3u8},{StationName: CRI华语环球广播,URL: http://sk.cri.cn/hyhq.m3u8},{StationName: CRI南海之声,URL: http://sk.cri.cn/nhzs.m3u8},{StationName: CRI世界华声,URL: http://sk.cri.cn/hxfh.m3u8}] 音频分发服务器 构建了一个HLS 音频测试平台用于测试。 后台nodeJS 编写 前端 使用hlv.js 插件 自制HLS 媒体
除了网络上的节目源之外我们也制作了一些测试语音媒体。要使用ffmpeg 工具转换。
使用ffmpeg 将mp3 转换成m3u8 的分段1.mp3
ffmpeg -i 1.mp3 -c:v libx264 -c:a aac -strict -2 -f hls -hls_list_size 2 -hls_time 15 1.m3u8
生成的效果是 将 1.mp3 视频文件每 15 秒生成一个 ts 文件最后生成一个 m3u8 文件1.m3u8)m3u8 文件是 ts 的索引文件。和两个ts 1.m3u8 ,10.ts 和11.ts
将生成的文件放置在nodeJS/public/media 目录中。
我的代码
NodeJS代码
import express from express;
import path from path
import url from url
import fs from fs;
const router express.Router();
const app express();
const __filename url.fileURLToPath(import.meta.url);
const __dirname path.dirname(__filename);
app.use(express.static(path.join(__dirname, public)));
app.use(express.json())router.get(/index, function (req, res) {res.sendFile(path.join(__dirname /views/index.html));
});
router.post(/getStations, async function (req, res) {Request req.body;// console.log(Request)const Method Request.Method;const StationsJSON.parse(fs.readFileSync(public/doc/StationTable.json,utf8))console.log(Stations)res.send(JSON.stringify({Method: getStations,Result: { Status: OK, Stations: JSON.stringify(Stations) }}))
});
app.use(/, router);
app.listen(process.env.port || 3000);
console.log(Running at Port 3000);前端Index.html
!DOCTYPE html
html langenheadmeta charsetutf-8meta nameviewport contentwidthdevice-width, initial-scale1.0titleRadio Player/titlelink relstylesheet hrefcss/bootstrap.min.csslink relstylesheet hrefcss/font-awesome.min.csslink relstylesheet hreffont/bootstrap-icons.cssscript srcjs/jquery-3.4.1.min.js/scriptscript srcjs/bootstrap.min.js/scriptscript srcjs/hls.js/scriptscript srcjs/jquery.mousewheel.min.js/scriptstyleselect {font-size: 24px;width: 320px;}audio {width: 320px;}/stylescriptvar hlsvar CurrentChannel0$(document).ready(function () {$(#Title).click()var audio document.getElementById(audio);hls new Hls();$(#Title).mousewheel(Mousewheel) getStations()});var Stations nullfunction Mousewheel(event){console.log(event.deltaX, event.deltaY, event.deltaFactor);if (event.deltaY0) {CurrentChannel;if (CurrentChannel64) CurrentChannel0}else {if (CurrentChannel0) CurrentChannel64elseCurrentChannel--;}$(#Selection).get(0).selectedIndexCurrentChannelSelected()}function getStations() {var parameter {Method: getStations,}$.ajax({url: /getStations,type: post,contentType: application/json,dataType: json,data: JSON.stringify(parameter),success: function (response) {Stations JSON.parse(response.Result.Stations)console.log(Stations)for (let i 0; i Stations.length; i) {$(#Selection).append(option Stations[i].StationName /option)}$(#Selection).get(0).selectedIndexCurrentChannelSelected()}})}function Selected() {const StationName $(#Selection).val()const Index $(#Selection).get(0).selectedIndexCurrentChannelIndexconsole.log(StationName)console.log(Index)if (Hls.isSupported()) {var audio document.getElementById(audio);hls.loadSource(Stations[Index].URL);hls.attachMedia(audio);hls.on(Hls.Events.MANIFEST_PARSED, function () {audio.play();});}}/script/headbodydiv classcontainer h1 classtext-info idTitle网络收音机/h1div classform-grouph3 classtext-info选台/h3select classform-select aria-labelDefault select idSelection onchangeSelected()/select/divdivh3 classtext-info播放器/h3audio idaudio controls /audio/div/div
/body/html
界面有点丑 结束语
下一步开始研究个人定制的音频频道的构建和尝试。感兴趣的可以共同探讨。