Java SourceDataLine 播放音频 显示频谱

Java SourceDataLine 播放MP3音频 显示频谱

  • 1 添加依赖
  • 2 快速傅里叶变换
    • 2.1 FFT.java
    • 2.2 Complex.java
  • 3 音频播放
    • 3.1 Player.java
    • 3.1 XPlayer.java
  • 4 显示频谱
  • 5 结果

项目Value
音频格式 添加依赖
*.wav(JDK 原生支持)
*.pcm(JDK 原生支持)
*.au(JDK 原生支持)
*.aiff(JDK 原生支持)
*.mp3mp3spi.jar
*.flacjflac-codec.jar

1 添加依赖

<dependency><groupId>com.googlecode.soundlibs</groupId><artifactId>mp3spi</artifactId><version>1.9.5.4</version>
</dependency><!-- 如果需要解码播放flac文件则引入这个jar包 -->
<dependency><groupId>org.jflac</groupId><artifactId>jflac-codec</artifactId><version>1.5.2</version>
</dependency>

2 快速傅里叶变换

2.1 FFT.java

package com.xu.music.player.fft;import java.util.stream.Stream;public class FFT {/*** compute the FFT of x[], assuming its length is a power of 2** @param x* @return*/public static Complex[] fft(Complex[] x) {int n = x.length;// base caseif (n == 1) {return new Complex[]{x[0]};}// radix 2 Cooley-Tukey FFTif (n % 2 != 0) {throw new RuntimeException("N is not a power of 2");}// fft of even termsComplex[] even = new Complex[n / 2];for (int k = 0; k < n / 2; k++) {even[k] = x[2 * k];}Complex[] q = fft(even);// fft of odd termsComplex[] odd = even; // reuse the arrayfor (int k = 0; k < n / 2; k++) {odd[k] = x[2 * k + 1];}Complex[] r = fft(odd);// combineComplex[] y = new Complex[n];for (int k = 0; k < n / 2; k++) {double kth = -2 * k * Math.PI / n;Complex wk = new Complex(Math.cos(kth), Math.sin(kth));y[k] = q[k].plus(wk.times(r[k]));y[k + n / 2] = q[k].minus(wk.times(r[k]));}return y;}/*** compute the inverse FFT of x[], assuming its length is a power of 2** @param x* @return*/public static Complex[] ifft(Complex[] x) {int n = x.length;Complex[] y = new Complex[n];// take conjugatefor (int i = 0; i < n; i++) {y[i] = x[i].conjugate();}// compute forward FFTy = fft(y);// take conjugate againfor (int i = 0; i < n; i++) {y[i] = y[i].conjugate();}// divide by Nfor (int i = 0; i < n; i++) {y[i] = y[i].scale(1.0 / n);}return y;}/*** compute the circular convolution of x and y** @param x* @param y* @return*/public static Complex[] cconvolve(Complex[] x, Complex[] y) {// should probably pad x and y with 0s so that they have same length and are powers of 2if (x.length != y.length) {throw new RuntimeException("Dimensions don't agree");}int n = x.length;// compute FFT of each sequence,求值Complex[] a = fft(x);Complex[] b = fft(y);// point-wise multiply,点值乘法Complex[] c = new Complex[n];for (int i = 0; i < n; i++) {c[i] = a[i].times(b[i]);}// compute inverse FFT,插值return ifft(c);}/*** compute the linear convolution of x and y** @param x* @param y* @return*/public static Complex[] convolve(Complex[] x, Complex[] y) {Complex zero = new Complex(0, 0);// 2n次数界,高阶系数为0.Complex[] a = new Complex[2 * x.length];for (int i = 0; i < x.length; i++) {a[i] = x[i];}for (int i = x.length; i < 2 * x.length; i++) {a[i] = zero;}Complex[] b = new Complex[2 * y.length];for (int i = 0; i < y.length; i++) {b[i] = y[i];}for (int i = y.length; i < 2 * y.length; i++) {b[i] = zero;}return cconvolve(a, b);}/*** Complex[] to double array for MusicPlayer** @param x* @return*/public static Double[] array(Complex[] x) {//for MusicPlayerint len = x.length;//修正幅过小 输出幅值 * 2 / length * 50return Stream.of(x).map(a -> a.abs() * 2 / len * 50).toArray(Double[]::new);}/*** display an array of Complex numbers to standard output** @param x* @param title*/public static void show(Double[] x, String... title) {for (String s : title) {System.out.print(s);}System.out.println();System.out.println("-------------------");for (int i = 0, len = x.length; i < len; i++) {System.out.println(x[i]);}System.out.println();}/*** display an array of Complex numbers to standard output** @param x* @param title*/public static void show(Complex[] x, String title) {System.out.println(title);System.out.println("-------------------");for (int i = 0, len = x.length; i < len; i++) {// 输出幅值需要 * 2 / lengthSystem.out.println(x[i].abs() * 2 / len);}System.out.println();}/*** 将数组数据重组成2的幂次方输出** @param data* @return*/public static Double[] pow2DoubleArr(Double[] data) {// 创建新数组Double[] newData = null;int dataLength = data.length;int sumNum = 2;while (sumNum < dataLength) {sumNum = sumNum * 2;}int addLength = sumNum - dataLength;if (addLength != 0) {newData = new Double[sumNum];System.arraycopy(data, 0, newData, 0, dataLength);for (int i = dataLength; i < sumNum; i++) {newData[i] = 0d;}} else {newData = data;}return newData;}/*** 去偏移量** @param originalArr 原数组* @return 目标数组*/public static Double[] deskew(Double[] originalArr) {// 过滤不正确的参数if (originalArr == null || originalArr.length <= 0) {return null;}// 定义目标数组Double[] resArr = new Double[originalArr.length];// 求数组总和Double sum = 0D;for (int i = 0; i < originalArr.length; i++) {sum += originalArr[i];}// 求数组平均值Double aver = sum / originalArr.length;// 去除偏移值for (int i = 0; i < originalArr.length; i++) {resArr[i] = originalArr[i] - aver;}return resArr;}}

2.2 Complex.java

package com.xu.music.player.fft;import java.util.Objects;public class Complex {private final double re; // the real partprivate final double im; // the imaginary part// create a new object with the given real and imaginary partspublic Complex(double real, double imag) {re = real;im = imag;}// a static version of pluspublic static Complex plus(Complex a, Complex b) {double real = a.re + b.re;double imag = a.im + b.im;Complex sum = new Complex(real, imag);return sum;}// sample client for testingpublic static void main(String[] args) {Complex a = new Complex(3.0, 4.0);Complex b = new Complex(-3.0, 4.0);System.out.println("a            = " + a);System.out.println("b            = " + b);System.out.println("Re(a)        = " + a.re());System.out.println("Im(a)        = " + a.im());System.out.println("b + a        = " + b.plus(a));System.out.println("a - b        = " + a.minus(b));System.out.println("a * b        = " + a.times(b));System.out.println("b * a        = " + b.times(a));System.out.println("a / b        = " + a.divides(b));System.out.println("(a / b) * b  = " + a.divides(b).times(b));System.out.println("conj(a)      = " + a.conjugate());System.out.println("|a|          = " + a.abs());System.out.println("tan(a)       = " + a.tan());}// return a string representation of the invoking Complex object@Overridepublic String toString() {if (im == 0) {return re + "";}if (re == 0) {return im + "i";}if (im < 0) {return re + " - " + (-im) + "i";}return re + " + " + im + "i";}// return abs/modulus/magnitudepublic double abs() {return Math.hypot(re, im);}// return angle/phase/argument, normalized to be between -pi and pipublic double phase() {return Math.atan2(im, re);}// return a new Complex object whose value is (this + b)public Complex plus(Complex b) {Complex a = this; // invoking objectdouble real = a.re + b.re;double imag = a.im + b.im;return new Complex(real, imag);}// return a new Complex object whose value is (this - b)public Complex minus(Complex b) {Complex a = this;double real = a.re - b.re;double imag = a.im - b.im;return new Complex(real, imag);}// return a new Complex object whose value is (this * b)public Complex times(Complex b) {Complex a = this;double real = a.re * b.re - a.im * b.im;double imag = a.re * b.im + a.im * b.re;return new Complex(real, imag);}// return a new object whose value is (this * alpha)public Complex scale(double alpha) {return new Complex(alpha * re, alpha * im);}// return a new Complex object whose value is the conjugate of thispublic Complex conjugate() {return new Complex(re, -im);}// return a new Complex object whose value is the reciprocal of thispublic Complex reciprocal() {double scale = re * re + im * im;return new Complex(re / scale, -im / scale);}// return the real or imaginary partpublic double re() {return re;}public double im() {return im;}// return a / bpublic Complex divides(Complex b) {Complex a = this;return a.times(b.reciprocal());}// return a new Complex object whose value is the complex exponential of// thispublic Complex exp() {return new Complex(Math.exp(re) * Math.cos(im), Math.exp(re) * Math.sin(im));}// return a new Complex object whose value is the complex sine of thispublic Complex sin() {return new Complex(Math.sin(re) * Math.cosh(im), Math.cos(re) * Math.sinh(im));}// return a new Complex object whose value is the complex cosine of thispublic Complex cos() {return new Complex(Math.cos(re) * Math.cosh(im), -Math.sin(re) * Math.sinh(im));}// return a new Complex object whose value is the complex tangent of thispublic Complex tan() {return sin().divides(cos());}// See Section 3.3.@Overridepublic boolean equals(Object x) {if (x == null) {return false;}if (this.getClass() != x.getClass()) {return false;}Complex that = (Complex) x;return (this.re == that.re) && (this.im == that.im);}// See Section 3.3.@Overridepublic int hashCode() {return Objects.hash(re, im);}
}

3 音频播放

3.1 Player.java

package com.xu.music.player.player;import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioFormat.Encoding;
import javax.sound.sampled.AudioInputStream;import java.io.File;
import java.net.URL;/*** Java 音频播放** @author hyacinth* @date 2019年10月31日19:06:39*/
public interface Player {/*** Java Music 加载音频** @param url 音频文件url* @throws Exception 异常* @date 2019年10月31日19:06:39*/void load(URL url) throws Exception;/*** Java Music 加载音频** @param file 音频文件* @throws Exception 异常* @date 2019年10月31日19:06:39*/void load(File file) throws Exception;/*** Java Music 加载音频** @param path 文件路径* @throws Exception 异常* @date 2019年10月31日19:06:39*/void load(String path) throws Exception;/*** Java Music 加载音频** @param stream 音频文件输入流* @throws Exception 异常* @date 2019年10月31日19:06:39*/void load(AudioInputStream stream) throws Exception;/*** Java Music 加载音频** @param encoding Encoding* @param stream   AudioInputStream* @throws Exception 异常* @date 2019年10月31日19:06:39*/void load(Encoding encoding, AudioInputStream stream) throws Exception;/*** Java Music 加载音频** @param format AudioFormat* @param stream AudioInputStream* @throws Exception 异常* @date 2019年10月31日19:06:39*/void load(AudioFormat format, AudioInputStream stream) throws Exception;/*** Java Music 暂停播放** @date 2019年10月31日19:06:39*/void pause();/*** Java Music 继续播放** @date 2019年10月31日19:06:39*/void resume();/*** Java Music 开始播放** @throws Exception 异常* @date 2019年10月31日19:06:39*/void play() throws Exception;/*** Java Music 结束播放** @description: Java Music 结束播放* @date 2019年10月31日19:06:39*/void stop();}

3.1 XPlayer.java

package com.xu.music.player.player;import cn.hutool.core.io.IoUtil;
import cn.hutool.core.text.CharSequenceUtil;
import javazoom.spi.mpeg.sampled.file.MpegAudioFileReader;import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.LinkedList;/*** Java 音频播放** @author hyacinth* @date 2019年10月31日19:06:39*/
public class XPlayer implements Player {private static SourceDataLine data = null;private static AudioInputStream audio = null;public static volatile LinkedList<Double> deque = new LinkedList<>();public void put(Double v) {synchronized (deque) {deque.add(Math.abs(v));if (deque.size() > 90) {deque.removeFirst();}}}private XPlayer() {}public static XPlayer createPlayer() {return XPlayer.SingletonHolder.player;}private static class SingletonHolder {private static final XPlayer player = new XPlayer();}@Overridepublic void load(URL url) throws Exception {load(AudioSystem.getAudioInputStream(url));}@Overridepublic void load(File file) throws Exception {String name = file.getName();if (CharSequenceUtil.endWithIgnoreCase(name, ".mp3")) {AudioInputStream stream = new MpegAudioFileReader().getAudioInputStream(file);AudioFormat format = stream.getFormat();format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(),format.getChannels() * 2, format.getSampleRate(), false);stream = AudioSystem.getAudioInputStream(format, stream);load(stream);} else if (CharSequenceUtil.endWithIgnoreCase(name, ".flac")) {AudioInputStream stream = AudioSystem.getAudioInputStream(file);AudioFormat format = stream.getFormat();format = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), 16, format.getChannels(),format.getChannels() * 2, format.getSampleRate(), false);stream = AudioSystem.getAudioInputStream(format, stream);load(stream);} else {load(AudioSystem.getAudioInputStream(file));}}@Overridepublic void load(String path) throws Exception {load(new File(path));}@Overridepublic void load(AudioInputStream stream) throws Exception {DataLine.Info info = new DataLine.Info(SourceDataLine.class, stream.getFormat(), AudioSystem.NOT_SPECIFIED);data = (SourceDataLine) AudioSystem.getLine(info);data.open(stream.getFormat());audio = stream;}@Overridepublic void load(AudioFormat.Encoding encoding, AudioInputStream stream) throws Exception {load(AudioSystem.getAudioInputStream(encoding, stream));}@Overridepublic void load(AudioFormat format, AudioInputStream stream) throws Exception {load(AudioSystem.getAudioInputStream(format, stream));}@Overridepublic void pause() {}@Overridepublic void resume() {}@Overridepublic void play() throws IOException {if (null == audio || null == data) {return;}data.start();byte[] buf = new byte[4];int channels = audio.getFormat().getChannels();float rate = audio.getFormat().getSampleRate();while (audio.read(buf) != -1) {if (channels == 2) {//立体声if (rate == 16) {put((double) ((buf[1] << 8) | buf[0]));//左声道//put((double) ((buf[3] << 8) | buf[2]));//右声道} else {put((double) buf[1]);//左声道put((double) buf[3]);//左声道//put((double) buf[2]);//右声道//put((double) buf[4]);//右声道}} else {//单声道if (rate == 16) {put((double) ((buf[1] << 8) | buf[0]));put((double) ((buf[3] << 8) | buf[2]));} else {put((double) buf[0]);put((double) buf[1]);put((double) buf[2]);put((double) buf[3]);}}data.write(buf, 0, 4);}}@Overridepublic void stop() {if (null == audio || null == data) {return;}IoUtil.close(audio);data.stop();IoUtil.close(data);}}

4 显示频谱

package com.xu.music.player.test;import cn.hutool.core.collection.CollUtil;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;import java.io.File;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;import com.xu.music.player.fft.Complex;
import com.xu.music.player.fft.FFT;
import com.xu.music.player.player.Player;
import com.xu.music.player.player.XPlayer;/*** SWT Composite 绘画** @date 2024年2月2日19点27分* @since V1.0.0.0*/
public class SwtDraw {private Shell shell = null;private Display display = null;private Composite composite = null;private final Random random = new Random();private final List<Integer> spectrum = new LinkedList<>();public static void main(String[] args) {SwtDraw test = new SwtDraw();test.open();}/*** 测试播放*/public void play() {try {Player player = XPlayer.createPlayer();player.load(new File("D:\\Kugou\\梦涵 - 加减乘除.mp3"));new Thread(() -> {try {player.play();} catch (Exception e) {throw new RuntimeException(e);}}).start();} catch (Exception e) {}}/*** 打开 SWT 界面** @date 2024年2月2日19点27分* @since V1.0.0.0*/public void open() {display = Display.getDefault();createContents();shell.open();shell.layout();play();task();while (!shell.isDisposed()) {if (!display.readAndDispatch()) {display.sleep();}}}/*** 设置 SWT Shell内容** @date 2024年2月2日19点27分* @since V1.0.0.0*/protected void createContents() {shell = new Shell(display);shell.setSize(900, 500);shell.setLayout(new FillLayout(SWT.HORIZONTAL));// 创建一个Compositecomposite = new Composite(shell, SWT.NONE);// 添加绘图监听器composite.addPaintListener(listener -> {GC gc = listener.gc;int width = listener.width;int height = listener.height;int length = width / 25;if (spectrum.size() >= length) {for (int i = 0; i < length; i++) {draw(gc, i * 25, height, 25, spectrum.get(i));}}});}/*** 模拟 需要绘画的数据 任务** @date 2024年2月2日19点27分* @since V1.0.0.0*/public void task() {Timer timer = new Timer(true);timer.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {display.asyncExec(() -> {if (!composite.isDisposed()) {// 在这里调用你更新数据的方法updateData();// 重绘composite.redraw();}});}}, 0, 100);}/*** 模拟 更新绘画的数据** @date 2024年2月2日19点27分* @since V1.0.0.0*/public void updateData() {spectrum.clear();if (CollUtil.isEmpty(XPlayer.deque)) {return;}Complex[] x = new Complex[XPlayer.deque.size()];for (int i = 0; i < x.length; i++) {try {x[i] = new Complex(XPlayer.deque.get(i), 0);} catch (Exception e) {x[i] = new Complex(0, 0);}}Double[] value = FFT.array(x);for (double v : value) {spectrum.add((int) v);}}/*** Composite 绘画** @param gc     GC* @param x      x坐标* @param y      y坐标* @param width  宽度* @param height 高度* @date 2024年2月2日19点27分* @since V1.0.0.0*/private void draw(GC gc, int x, int y, int width, int height) {// 设置条形的颜色Color color = new Color(display, random.nextInt(255), random.nextInt(255), random.nextInt(255));gc.setBackground(color);// 绘制条形Rectangle draw = new Rectangle(x, y, width, -height);gc.fillRectangle(draw);// 释放颜色资源color. Dispose();}}

5 结果

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/695050.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3项目引入本地js文件,实现一个音频播放按钮

目前有一个需求就是在网页上放置一个音乐控制按钮&#xff0c;并且是在vue3项目里面。于是小白的我遇到了2个问题&#xff0c;第一个问题是如何实现没有进度条的播放按钮&#xff0c;这个网上有现成的代码&#xff0c;可以通过js代码切换不同的图片或者是别的样式&#xff0c;并…

SparkSQL学习02-编程入口

文章目录 1 DataFrame的构建方式方式一&#xff1a;JavaBean反射的方式1.1 创建Scala类1.2 创建Scala对象 方式二&#xff1a;动态编码的方式 2 DataSet的构建方式3 RDD和DataFrame以及DataSet之间的相互转换3.1【RDD-->DataFrame】和【RDD-->DataSet】3.2【DataFrame--&…

java基础之 SPI机制

SPI机制说明 什么是SPI Service Provider Interface 机制是Java提供的一套用来被第三方实现或扩展的API&#xff0c;他可以用来启用框架扩展和替换组件。通过“基于接口的编程 策略模式 配置文件”组合实现的动态加载机制。SPI机制为某个接口寻找服务实现的机制&#xff0c;…

二叉树基础知识总结

目录 二叉树基础知识 概念 : 根节点的五个形态 : 特殊的二叉树 满二叉树 : 完全二叉树 : 二叉搜索树 : 平衡二叉搜索树 : 二叉树的性质 : 二叉树的存储结构 二叉树的顺序存储结构 二叉树的链式存储结构 二叉树的遍历方式 : 基础概念 前中后遍历 层序遍历 :…

【Redis】理论进阶篇------浅谈Redis的缓存穿透和雪崩原理

一、缓存穿透 1、概念 缓存穿透&#xff08;查不到数据&#xff09;&#xff0c;是指当用户想要查询数据的时候&#xff0c;会先去Redis中取命中&#xff0c;如果Redis中没有该数据&#xff0c;那么就会向数据库中去查找数据。如果数据库中也没有&#xff0c;则该次查询结果失…

Spring学习笔记(五)--Spring的AOP模块

一、AOP的底层原理 AOP的底层原理是动态代理&#xff0c;动态代理有两种方式&#xff1a;JDK动态代理和CGLib动态代理&#xff0c;在有接口的实现类时我们通常用JDK的动态代理方式&#xff08;默认情况&#xff09;为类创建代理对象&#xff0c;JDK的动态代理方式可以实现无入…

ORM中常用的字段和参数,正反向概念

django表查询测试环境搭建 首先&#xff0c;在此之前我们先来回顾一下之前学习的orm内容 1. django自带一个小型的sqlite3的小型数据库 但是这个数据库的功能非常有限&#xff0c;并且针对日期类型的数据兼容性很差 2. 切换数据库数据(MySQL) 2.1 在django1.x版本中你需要在_…

PotPlayer+Alist挂载并播放网盘视频

文章目录 说明技术WebDAVPotPlayer 操作步骤一&#xff1a;Alist开启WebDAV代理二&#xff1a;PotPlayer连接Alist 说明 Alist网页端播放视频受限&#xff0c;主要是文件大于20MB&#xff0c;由于官方限制&#xff0c;无法播放需要使用user-agent修改插件&#xff0c;设置百度…

《最新出炉》系列初窥篇-Python+Playwright自动化测试-24-处理单选和多选按钮-上篇

1.简介 在工作和生活中&#xff0c;经常会遇到我们需要进行选择的情况&#xff0c;比如勾选我们选择性别&#xff0c;男女两个性别总是不能同时选中的&#xff0c;再比如我们在选择兴趣爱好时&#xff0c;我们可以选择多个自己感兴趣的话题&#xff0c;比如&#xff1a;篮球、…

sqllabs第46关 order by 注入

简介&#xff1a;&#xff08;order by注入-错误回显-POST注入&#xff09; 请求方法&#xff1a;POST 方法&#xff1a;order by注入错误回显数字型注入 先了解下 order by参数注入&#xff1a; order by 注入是指其后面的参数是可控的&#xff0c; order by 不同于我们在 whe…

gem5学习(23):经典缓存——Classic Caches

目录 一、Interconnects 1、Crossbars 二、Debugging 官网教程&#xff1a;gem5: Classic caches 默认缓存是一个带有MSHR&#xff08;未命中状态保持寄存器&#xff09;和WB&#xff08;写缓冲区&#xff09;的非阻塞缓存&#xff0c;用于读取和写入未命中。缓存还可以启用…

[java基础揉碎]this

引出this: 什么是this: java虚拟机会给每个对象分配 this&#xff0c;代表当前对象。 这里的this就是new出来的这个对象 this的本质: this是个引用在堆中指向它自己: this的细节: 访问成员方法: 访问构造器:

精英ECS Z97-MACHINE V1.0 BIOS MX25L6406E

官网上的两个BIOS我都无法亮机&#xff0c;这是我保存出来的BIOS&#xff0c;不知道是否能使用五代的处理器 官网&#xff1a;Z97-MACHINE&#xff5c;Motherboard&#xff5c;产品&#xff5c;ECS 精英电脑 国外老哥的看法&#xff1a;ECS Z97-MACHINE Closer Look: The BIO…

RocketMQ-架构与设计

RocketMQ架构与设计 一、简介二、框架概述1.设计特点 三、架构图1.Producer2.Consumer3.NameServer4.BrokerServer 四、基本特性1.消息顺序性1.1 全局顺序1.2 分区顺序 2.消息回溯3.消息重投4.消息重试5.延迟队列&#xff08;定时消息&#xff09;6.重试队列7.死信队列8.消息语…

【电子书】游戏开发

资料 wx&#xff1a;1945423050 整理了一些互联网电子书&#xff0c;推荐给大家 游戏开发 ADOBE FLASH PROFESSIONAL CS6 标准培训教材.epubAndroid 3D 游戏案例开发大全.epubCocos Creator游戏开发实战.epubCocos2D-X游戏开发技术精解.epubCocos2d-JS游戏开发快速入门到实战…

《Python 语音转换简易速速上手小册》第3章 文本到语音的转换(2024 最新版)

文章目录 3.1 文本到语音的原理3.1.1 基础知识3.1.2 主要案例&#xff1a;自动新闻播报器案例介绍案例 Demo案例分析 3.1.3 扩展案例 1&#xff1a;智能助手案例介绍案例 Demo案例分析 3.1.4 扩展案例 2&#xff1a;电子书阅读器案例介绍案例 Demo案例分析 3.2 Python 中的文本…

python 验证AES_ECB算法对数据的加解密

目录 一、python 代码实现如下&#xff1a; 二、代码解析 三、运行结果 一、python 代码实现如下&#xff1a; #AES_ECB模式实现 from Crypto.Cipher import AES from Crypto.Random import get_random_bytes # 自动生成密钥 from Crypto.Util.Padding import pad, unpad …

开开开开开,干

大家新年快乐&#xff0c;开工啦啦啦啦 其实每天很多人都会问&#xff1a; 有协同过滤的算法吗&#xff0c;有的&#xff0c;可以给你解释原理… 有的小伙伴只开了一部分逻辑&#xff0c;我要实现用户可以下单功能 但是细细考虑下单&#xff0c;需要现有用户&#xff0c;维护…

为全志D1开发板移植LVGL日历控件和显示天气

利用TCP封装HTTP包请求天气信息 Linux还真是逐步熟悉中&#xff0c;现在才了解到Linux即没有原生的GUI&#xff0c;也没有应用层协议栈&#xff0c;所以要实现HTTP应用&#xff0c;必须利用TCP然后自己封装HTTP数据包。本篇即记录封装HTTP数据包&#xff0c;到心知天气请求天气…

Flutter Slider自定义滑块样式 Slider的label标签框常显示

1、自定义Slider滑块样式 Flutter Slider控件的滑块系统样式是一个圆点&#xff0c;thumbShape默认样式是RoundSliderThumbShape&#xff0c;如果想要使用其它的样式就需要自定义一下thumbShape&#xff1b; 例如需要一个上图样式的&#xff08;圆点半透明圆形边框&#xff09…